专栏文章

题解:CF1092E Minimal Diameter Forest

CF1092E题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@miqkdrpz
此快照首次捕获于
2025/12/04 06:14
3 个月前
此快照最后确认于
2025/12/04 06:14
3 个月前
查看原文

思路:

首先根据贪心策略,我们知道最后的结果是由每棵树的直径共同决定的。因此,我们把每棵树的直径的重点当作它的根,然后再次贪心,把选择一棵直径最长的树,把它的根和其他树的根项链,最后再求一边全部树的直径即可。

难点分析:

贪心策略;树的直径的求法;菊花图。

代码:

树的直径模板:
CPP
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,x,y,pos=1,d[200005];
vector<int>g[200005];
void dfs(int u,int fa){
	d[u]=d[fa]+1;
	if(d[u]>d[pos])pos=u;
	for(int i:g[u]){
		if(i!=fa)dfs(i,u);
	}
}
signed main () {
	cin>>n;
	for(int i=1;i<n;i++){
		scanf("%lld%lld",&x,&y);
		g[x].push_back(y);
		g[y].push_back(x);
	}
	dfs(1,0);
	dfs(pos,0);
	cout<<d[pos]-1;
	return 0;
}
本题代码:
CPP
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
int t,n,m,x,y,fa[1005],d[1005],pos,len[1005],cen[1005],cnt,s,maxa=-1e9;
vector<int>g[200005];
vector<pii>ans;
bool vis[200005];
int find(int x){
	if(fa[x]==x)return x;
	return fa[x]=find(fa[x]);
}//每棵树的分类 
void dfs(int u,int fa){
	d[u]=d[fa]+1;
	if(d[u]>d[pos])pos=u;
	for(int i:g[u]){
		if(i!=fa)dfs(i,u);
	}
}//求直径 
void get(int u,int fa,int halflen){
	if(d[u]-1==halflen){
		cnt=u;
		return ;
	}
	for(int i:g[u]){
		if(i!=fa)get(i,u,halflen);
	}
}//求中点 
signed main () {
	cin>>n>>m; 
	for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=1;i<=m;i++){
		scanf("%lld%lld",&x,&y);
		g[x].push_back(y);
		g[y].push_back(x);
		fa[find(x)]=find(y);
	}
	for(int i=1;i<=n;i++){
		if(!vis[find(i)]){
			vis[find(i)]=1;
			pos=find(i);
			dfs(find(i),0);
			dfs(pos,0);
			len[find(i)]=d[pos]-1;//len是每棵树的直径 
			cnt=find(i);
			get(pos,0,len[find(i)]/2);
			cen[find(i)]=cnt;//每棵树的直径的中点 
			if(len[find(i)]%2==0)x=len[find(i)]/2;
			else x=len[find(i)]/2+1;//直径长度的奇偶性需要分类讨论,但是长度为奇数时选择两个点作为根都是一样的 
			if(x>maxa){
				maxa=x;
				s=cen[find(i)];
			} 
		} 
	} //找每棵树直径的中点 ,s是所有树的根集中的那一点 
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++){
		if(!vis[find(i)]){
			vis[find(i)]=1;
			if(cen[find(i)]!=s){
				g[cen[find(i)]].push_back(s);
				g[s].push_back(cen[find(i)]);
				ans.push_back({s,cen[find(i)]});//连每棵树的根,并记录答案 
			}
		}
	} 
	pos=1;
	dfs(1,0);
	dfs(pos,0);//再次求直径 
	cout<<d[pos]-1<<endl;
	for(pii i:ans)cout<<i.first<<" "<<i.second<<endl;
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...