题解 CF120F 【Spiders】
题外话:
这道题目的翻译有点小问题,翻译没有说要开文件,但是题目是要求开文件的!我因为这个错了一次,看到错误信息才会看题目发现要开文件:
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
这是应该开的文件
解题思路:
这道题的大意就是给我们\(n\)棵树,让我们任意合并这\(n\)棵树,问能得到的最大直径。很显然的贪心,就是我们每次都把直径拼接在一起,然后最后的答案其实就是\(n\)棵树的直径长度和,我们也根本不用模拟拼接的过程。
对于无根树找直径的方法:
有两种,一种是(两次BFSor两次DFS),一种是树形DP,这里介绍两次DFS版的
首先任意取一个节点(我是随机rand()了一个节点),进行一次DFS,找出离它最远的点假设为\(p\),然后再以\(p\)为起点进行一次DFS,找出离\(p\)最远的点\(q\),这时候,\(p\)到\(q\)的路径形成的就是树的直径.
Code
#include <bits/stdc++.h>
using namespace std;
int T,n,p,v,m = 0;
struct Edge{
int next,to;
}edge[10005];
int head[1000];
int deep[1005];
void add_edge(int from,int to)
{
m ++;
edge[m].to = to;
edge[m].next = head[from];
head[from] = m;
}
void DFS(int x,int from)
{
deep[x] = deep[from] + 1;
for(int i = head[x] ; i ; i = edge[i].next)
{
int to = edge[i].to;
if(!deep[to])DFS(to,x);
}
return ;
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
cin >> T;
int ans = 0;
while(T)
{
cin >> n;
m = 0;
memset(head,0,sizeof(head));
memset(deep,0,sizeof(deep));
for(int i = 1 ; i <= n-1; i ++)
{
int u,v;
cin >> u >> v;
add_edge(u,v);
add_edge(v,u);
}
srand(time(NULL));
int s = rand() % n + 1;
DFS( s , 0 );
for(int i = 1 ; i <= n ; i ++)
if(deep[i] > deep[s]) s = i;//第一次DFS
memset(deep,0,sizeof(deep));
DFS( s , 0 );
for(int i = 1 ; i <= n ; i ++)
if(deep[i] > deep[s]) s = i;
ans += deep[s] - 1;
//第二次DFS,因为起点深度默认为1,所以统计答案要-1
T--;
}
cout << ans;
return 0;
}
By MYCui