转自:http://blog.csdn.net/qq_37957829/article/details/79587597
题目大意:给定一个树形图,n个节点,n-1条边,每一个小时内,可以把两个有相同父节点的并且不相连的两个节点连接,要经过多少个小时才可以把整个图变成全连通图。
解题的方法肯定不是模拟,就时间复杂度就接受不了模拟,所以要有技巧。我们可以想象,要全连通,那么该图中相距最远的两个点一定也要连接起来,并且它们是花费时间最长的两个点,所以我们只需要求出这最远的两个点需要多少时间连接就是全连通的时间,根据连接的方法,每次只能相同父节点的两个点相连,例如一条最长路(连续相连的9个点):(1,2,3,4,5,6,7,8,9),第一步连接(1,3),(2,4),(3,5)…,(7,9),这个时候第二步连接(1,5)(2,6)(3,7)(4,8),(5,9),第三步的时候(1,9).1号和9号就连接起来了,每一步的跨度逐渐变大,增长的速度是2^n 。所以我们找到最长路的长度,再和2^n比较,向上取整。就是需要的时间。
求树形结构中最长路的方法就是利用两次BFS,第一次BFS从任意点出发,第二次BFS从第一次求得的最远点出发。第一次求得的最远点一定是在最长路的路径上。所以再一次BFS求得的长度就是最长路径。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 500000+5;
vector<int> edge[maxn];
int color[maxn],w[maxn],fuck;
void bfs(int s)
{
queue<int> q;
memset(w,0,sizeof(w));
memset(color,0,sizeof(color));
color[s] = 1;
w[s] = 0;
q.push(s);
while(!q.empty())
{
int u = q.front();
q.pop();
fuck = u;
int len = edge[u].size();
for(int i=0; i<len; i++)
{
if(!color[edge[u][i]])
{
q.push(edge[u][i]);
color[edge[u][i]]=1;
w[edge[u][i]] = w[u]+1;
}
}
}
}
long long num[100];
int main()
{
//freopen("in.txt","r",stdin);
int n;
num[0]=1;
for(int i=1; i<61; i++)
{
num[i] = num[i-1]*2;
}
scanf("%d",&n);
int u,v;
if(n==2)
{
printf("0\n");
return 0;
}
for(int i=0; i<n-1; i++)
{
scanf("%d%d",&u,&v);
edge[u].push_back(v);
edge[v].push_back(u);
}
bfs(u);
bfs(fuck);
int ans = 1;
for(int i=2; i<61; i++)
{
if(w[fuck]<=num[i] && w[fuck]>num[i-1])
{
ans = i;
break;
}
}
printf("%d\n",ans);
return 0;
}