首页 > 代码库 > vijos 1476 旅游规划(csapc)

vijos 1476 旅游规划(csapc)

描述

W市的交通规划出现了重大问题,市政府下决心在全市的各大交通路口安排交通疏导员来疏导密集的车流。但由于人员不足,W市市长决定只在最需要安排人员的路口安放人员。具体说来,W市的交通网络十分简单,它包括n个交叉路口和n-1条街道,任意一条街道连接两个交叉路口,并且任意两个交叉路口之间都存在一条路径互相连接。经过长期调查结果显示如果一个交叉路口位于W市交通网的最长路径上,那么这个路口必然拥挤不堪,所谓最长路径定义为某条路径p=(v1,v2,v3…vk),路径经过的路口各不相同且城市中不存在长度>k的路径(因此可能存在着不唯一的最长路径)。因此W市市长希望知道有哪些路口位于城市交通网的最长路径之上。

格式

输入格式

第一行包括一个整数n。

之后的n-1行每行包括两个整数u, v表示编号为u和v的路口之间存在着一条街道(注意:路口被依次编号为0到n-1)

输出格式

输出包括若干行,每行包括一个整数——某个位于最长路上路口的编号。

为了确保解唯一,我们规定位于所有最长路上的路口按编号顺序从小到大输出。

样例1

样例输入1

10
0 1
0 2
0 4
0 6
0 7
1 3
2 5
4 8
6 9

样例输出1

0
1
2
3
4
5
6
8
9

提示

这里存在着若干条最长路径,其中的两条是3-1-0-2-5与8-4-0-6-9,他们的长度都是5,但是不存在长度>5的路径且所有最长路径都不包括路口7,所以答案中没有7。

数据范围:
对于50%的数据保证n<=1000
对于100%的数据保证n<=200000

解法:

一、dfs遍历一遍整棵树,求出每个结点到其最远子结点的距离f[N]及到其次远子结点的距离s[N](s[N]可以等于f[N])还有树的直径d。    

二、通过树形dp求出每个结点通过其父节点且不通过其子结点的最大距离up[N]。

三、对于每个结点通过他的最长的路径的长度为max(up[N]+f[N],s[N]+f[N])。(因为通过某一结点的路径要么穿过其父结点,要么不穿过,所以从这两种中取最大值就可以了)

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define R register
 4 #define N 200007
 5 using std::max;
 6 
 7 struct info{
 8   int to,pre;
 9 }edge[2*N];
10 
11 int read(){
12   int num=0;char c=getchar();
13   while (c<0||c>9) c=getchar();
14   while (c>=0&&c<=9) num=(num<<1)+(num<<3)+c-48,c=getchar();
15   return num;
16 }
17 
18 int n,ans,size,up[N],f[N],s[N],fa[N],head[N];
19 
20 void addline(int from,int to){
21   edge[++size].pre=head[from];head[from]=size;edge[size].to=to;
22   edge[++size].pre=head[to];head[to]=size;edge[size].to=from;
23 }
24 
25 void dfs(int k){
26   for (R int i=head[k];i;i=edge[i].pre)
27   if (edge[i].to!=fa[k]){
28       fa[edge[i].to]=k,dfs(edge[i].to);
29       if (f[edge[i].to]+1>f[k]) s[k]=f[k],f[k]=f[edge[i].to]+1;
30       else if (f[edge[i].to]+1>s[k]) s[k]=f[edge[i].to]+1;
31   }
32 }
33 
34 void tsdp(int k){
35   if (k!=0){
36       if (f[k]==(f[fa[k]]-1)) up[k]=max(s[fa[k]],up[fa[k]])+1;
37       else up[k]=max(f[fa[k]],up[fa[k]])+1;
38   }
39   for (R int i=head[k];i;i=edge[i].pre)
40    if (edge[i].to!=fa[k]) tsdp(edge[i].to);
41   if (up[k]+f[k]>ans) ans=up[k]+f[k];
42   if (f[k]+s[k]>ans) ans=s[k]+f[k];
43 }
44 
45 int main(){
46   n=read();
47   int u,v;
48   for (R int i=1;i<n;++i) u=read(),v=read(),addline(u,v);
49   dfs(0);
50   tsdp(0);
51   for (R int i=0;i<n;++i){
52       if ((up[i]+f[i]==ans)||(f[i]+s[i]==ans)) printf("%d\n",i);
53   }
54 }

测试地址:https://www.vijos.org/p/1476

vijos 1476 旅游规划(csapc)