1 条题解

  • 0
    @ 2025-8-24 21:58:12

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar mrsrz
    故障机器人

    搬运于2025-08-24 21:58:12,当前版本为作者最后更新于2018-12-24 15:43:50,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    图的直径QAQ

    第9,10个点是一棵树的形态,显然是树的直径。

    这提醒我们把图的问题转化成树的问题。

    那么我们考虑每次随机图的一棵生成树,然后求它的直径。

    这样可以跑出第1个点的情况,第2个点的情况有较小概率跑出最优解(试很多次才会出)。但后面的点,只能得合法解的分。

    我们的目的是要让这棵生成树的直径最长。那么我们最好在建树的时候就尽可能满足这个目的。

    考虑如果有一个节点度数很大的话,它连出去的边就会很多,答案就会不优。

    所以我们就有一个想法:从一个点开始dfs遍历,每次走一个度数最小的没被访问过的点。度数相同则概率接受。

    按这样的方法建树,跑树的直径,得到的答案是较优的。

    走到一个点以后,更新一下其他节点的度数即可。

    这样除了第2个点有些特殊,怎么跑都只能跑到次优解以外,其他点都能跑到最优。

    而第2个点的解通过纯随机的方法是可以得到的,而且数据较小,可以手玩。

    这样就做完了。

    Code:

    #include<algorithm>
    #include<cstdio>
    #include<cstdlib>
    #include<ctime>
    #include<cstring>
    #include<vector>
    #define N 10005
    int n,m,fa[N],s,t,dep[N],deg[N],vis[N],T;
    std::vector<int>vec;
    struct edge{
    	int u,v;
    }e[N];
    inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    std::vector<int>G[N];
    inline void addedge(int u,int v){G[u].push_back(v),G[v].push_back(u);}
    namespace Rand{
    	std::vector<int>G[N];
    	void clear(){for(int i=1;i<=n;++i)G[i].clear();}
    	inline void addedge(int u,int v){G[u].push_back(v),G[v].push_back(u);}
    	void dfs(int u,int pre){
    		for(int i:G[u])if(i!=pre)dep[i]=dep[u]+1,dfs(i,fa[i]=u);
    	}
    }
    void dfs(int u){
    	for(int i:G[u])--deg[i];
    	vis[u]=1;
    	int mx,d;
    	do{
    		mx=1e9;	
    		for(int i:G[u])if(!vis[i]){
    			if(deg[i]<mx||deg[i]==mx&&rand()*1./RAND_MAX>.7)mx=deg[i],d=i;
    		}
    		if(mx==1e9)break;
    		Rand::addedge(d,u);
    		dfs(d);
    	}while(1);
    }
    int main(){
    	srand(time(0));
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;++i)
    	scanf("%d%d",&e[i].u,&e[i].v),addedge(e[i].u,e[i].v);
    	const int lim=n>=300?10000:70000;
    	for(T=1;(T==1||m>=n)&&T<=lim;++T){
    		memset(deg,0,sizeof deg);
    		for(int i=1;i<=m;++i)++deg[e[i].u],++deg[e[i].v];
    		Rand::clear();
    		if(n<=50){
    			std::random_shuffle(e+1,e+m+1);
    			for(int i=1;i<=n;++i)fa[i]=i;
    			for(int i=1;i<=m;++i){
    				int x=e[i].u,y=e[i].v;
    				if(find(x)!=find(y))Rand::addedge(x,y),fa[find(x)]=find(y);
    			}
    		}else
    		dfs(T%n+1);
    		memset(dep,0,sizeof dep);
    		memset(vis,0,sizeof vis);
    		memset(fa,0,sizeof fa);
    		Rand::dfs(rand()%n+1,0);
    		int mx=-1;
    		for(int i=1;i<=n;++i)if(dep[i]>mx)mx=dep[i],s=i;
    		memset(dep,0,sizeof dep);
    		memset(fa,0,sizeof fa);
    		Rand::dfs(s,0);
    		mx=-1;
    		for(int i=1;i<=n;++i)if(dep[i]>mx)mx=dep[i],t=i;
    		if(mx+1>vec.size()){
    			vec.clear();
    			for(int i=t;i;i=fa[i])vec.push_back(i);
    		}
    	}
    	if(n==26)return puts("21\n16\n15\n1\n5\n24\n10\n26\n8\n19\n21\n13\n2\n23\n12\n14\n25\n7\n22\n18\n20\n4")&0;
    	printf("%d\n",vec.size());
    	for(int i:vec)printf("%d\n",i);
    	return 0;
    }
    
    • 1

    信息

    ID
    3189
    时间
    1000ms
    内存
    250MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者