题目描述
自从省队NOI赛前集训在scz举行之后,一个名叫cs1.6.exe的文件开始在机房广泛使用起来。每天大家都要找神犇小X借移动硬盘,考里面的这个文件。
由于机房里需要考这个文件的人太多了,每天都要花一段时间一个人一个人的去拷贝。小T觉得这实在是太麻烦了,就想找一个一劳永逸的方法。
小T调查了一下,机房有n台机器,且有局域网,所有机器通过一些网线连接起来,其整个布局是一个树形结构,即任意两台机器间都有且仅有一条路径。小T想在其中某一台机器上储存这个文件,需要的同学就可以直接通过局域网来下载这个文件。
网络上信息传输是需要时间的,我们定义两台机器间数据传输的时间为连接这两台机器的路径所包含的网线数量。虽然机房里通过局域网传个文件是很快的,但对于急不可耐的同学们来说,一分一秒都是宝贵的,文件传输越快越好。所以小T要选择一台机器存储文件,使得所有机器下载这个文件需要的总时间(即最后一台机器完成下载的时间)尽可能短。
现在,你需要给出这个最短时间,以便让小T看看他的决策是否最优。
输入
第1行:一个整数n。
第2~ n行:两个整数u、v,即u、v两台机器间有一条网线连接。机器从1~n编号。
输入数据保证是一个连通的树型结构。
输出
1行一个整数,即最短的时间。
输入样例
5
3 2
2 1
5 2
2 4
输出样例
1
说明
【数据范围】
对于30%的数据,n≤100;
对于50%的数据,n≤1000;
对于100%的数据,2≤n≤100000。
思路
这是一棵树,因为时间都是1,所以当做没边权
本题其实就是求(树的直径+1)/2
树的直径是树的最长路的长度
例如样例:
最长路是
1
→
2
→
3
o
r
5
o
r
4
1→2→3 or5or4
1→2→3or5or4
长度为
3
3
3
求树的直径有两种方法,DP和2*dfs,我的code用的是dfs,
DP
f
[
i
]
f[i]
f[i]为
i
i
i这个子树最长的路,动态转移方程是:
f
[
i
]
=
m
a
x
(
f
[
i
]
,
f
[
j
]
)
+
1
f[i]=max(f[i],f[j])+1
f[i]=max(f[i],f[j])+1(
j
j
j为
i
i
i的所有儿子)
在每一次
f
[
i
]
=
m
a
x
(
f
[
i
]
,
f
[
j
]
)
+
1
f[i]=max(f[i],f[j])+1
f[i]=max(f[i],f[j])+1前
加一个
a
n
s
=
m
a
x
(
a
n
s
,
f
[
i
]
+
f
[
j
]
)
ans=max(ans,f[i]+f[j])
ans=max(ans,f[i]+f[j])
就是以
i
i
i为根节点的树的直径
DFS则是
随机一个
l
l
l
DFS离
l
l
l点最远的点
r
r
r
再DFS离
r
r
r点最远的点
k
k
k
r
r
r点与
k
k
k点之间的距离就是这棵树的直径
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define INF 1e9
using namespace std;
int n,m,x,y,t,ans,ansd;
bool b[100005];
int h[100005];
struct whw
{
int w,h;
}wh[200005];
void hw(int x,int y)
{wh[++t]=(whw){x,h[y]};h[y]=t;}
void dfs(int k)
{
if(t>ans)ans=t,ansd=k;
for(int i=h[k];i;i=wh[i].h)
if(!b[wh[i].w])
{
b[wh[i].w]=1,++t;
dfs(wh[i].w);
b[wh[i].w]=0,--t;
}
}
int main()
{
int size = 256 << 20;
char*p=(char*)malloc(size) + size;
__asm__("movl %0, %%esp\n" :: "r"(p) );
//dalao说加了才能A,本蒟蒻也不知道什么意思
//麻烦有知道的dalao在评论栏里与我分享
scanf("%d",&n);
for(int i=1;i<=n-1;++i)
{
scanf("%d%d",&x,&y);
hw(x,y);hw(y,x);//建边
}
t=0;
dfs(1);dfs(ansd);
printf("%d",(ans+1)/2);
return 0;
}