您的位置:首页 > 其它

Gym-100781A 【树的直径 + 思维】

2017-10-08 20:28 357 查看
传送门

//题意: 给你很多颗树(当然也可能只有一棵树), 问你怎样连接起来可以使得形成的树上最远的距离最小,并输出这个距离.

//思路: 当然是和树的直径有关, 然后可以知道从直径折半的地方连出去是最优的, 先用并查集求出每一棵树的直径. 然后需要讨论几种情况, 一是有一棵树它的直径本来就很长, 那么答案有可能是它, 然后(必须两棵树以上)就是直径第一长的和第二长的, 可能是一种答案, 还有一种就是(必须三棵树以上)以直径最长的树作为中转点, 第二长的和第三长的通过这个相连, 那么答案也可能是这种情况最优, 如果你要问为什么不以第三长的作为中转点的话, 那就是没懂起题意, 要让最远的距离最小, 所以只能这样, 细节请看代码.

AC Code

const int maxn = 1e5+5;
int cas=1;
int pre[maxn],vis[maxn];
int n,m;
vector<int>g[maxn];
int Find(int x)
{
return pre[x] == x?x: pre[x] = Find(pre[x]); //不要再写成 == 了!!!
}
int maxx;
int dfs(int u,int fa)
{
int fir = 0, sec = 0;
for(int i=0;i<g[u].size();i++){
int to = g[u][i];
if(to == fa) continue;
int tmp = dfs(to,u);
if(tmp > fir) sec = fir, fir = tmp;
else if(tmp > sec) sec = tmp;
}
if(fir + sec > maxx) maxx = fir + sec;
return fir + 1;
}
int d[maxn];
bool cmp(int a,int b)
{
return a > b;
}
void solve()
{
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++) g[i].clear(),pre[i] = i;
Fill(vis,0);
for(int i=1;i<=m;i++){
int u,v; scanf("%d%d",&u,&v);
u++; v++;
g[u].push_back(v);
g[v].push_back(u);
u = Find(u); v = Find(v);
if(u != v) pre[u] = v;
}
int idx = 0 ;
for(int i=1;i<=n;i++){ //并查集求每棵树的直径.
if(vis[Find(i)]) continue;
vis[Find(i)] = 1;
maxx = 0; dfs(i,-1);
d[idx++] = maxx;
}
sort(d,d+idx,cmp);
int res = d[0]; //第一种情况
if(idx > 1){    //第二种情况
res = max(res,(d[0] + 1)/2 + (d[1] + 1)/2 + 1);
}
if(idx > 2){    //第三种情况
res = max(res,(d[1] + 1)/2 + (d[2] + 1)/2 + 2);
}
printf("%d\n",res);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: