CSU 1681 Adjoin(树形dp && 树的直径)

来源:互联网 发布:ubuntu docker 编辑:程序博客网 时间:2024/06/05 22:38

题目链接:【CSU 1681】

一共有n个点,m条线,每条线将两个点连接在一起,导致这n个点中有些点是连通的有些点是不连通的,加入最少的线,使得n个点两两连通,求每两个点之间最大距离的最小值


树的直径:树上两个点之间的最大距离

每一个连通块就是一棵树,先求出每一棵树的直径,用数组d[]记录,然后从小到大排序,找到最大直径,合并树(直径小的合并到直径大的),更新最大直径

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <string>#include <vector>using namespace std;const int N=1e5+10;vector<int>vec[N];int vis[N], dis[N], maxn, id;int d[N];void dfs(int p, int u)  {  vis[u]=1;    for(int i = 0; i < vec[u].size(); i++)    {          int v = vec[u][i];        if(p != v)        {            dis[v] = dis[u] + 1;            if(maxn < dis[v])            {                maxn = dis[v];                id = v;            }            dfs(u, v);        }    }}int main(){int n, m;while(~scanf("%d%d", &n, &m)){for(int i=0; i<n; i++) vec[i].clear();memset(vis, 0, sizeof(vis));int a, b;for(int i=0; i<m; i++){scanf("%d%d", &a, &b);vec[a].push_back(b);vec[b].push_back(a);}int ans=0, len=0;for(int i=0; i<n; i++){if(!vis[i]){memset(dis, 0, sizeof(dis));maxn=0, id=-1;dfs(-1, i);//找到跟点i的距离最大的那个点 if(id!=-1)//id==-1,这棵树只有一个点,树的直径是0 {memset(dis, 0, sizeof(dis));dfs(-1, id);//求树的直径 }d[++len] = maxn;}}sort(d, d+len+1);ans = d[len];for(int i=len-1; i>=0; i--){ans = max((ans+1)/2+(d[i]+1)/2+1, ans);}if(n==1) ans=0;printf("%d\n", ans);}return 0;} /*6 40 10 23 43 511 90 10 30 41 25 46 47 87 97 10*/ 

0 0