试题描述 |
W 市的交通规划出现了重大问题,市政府下定决心在全市各大交通路口安排疏导员来疏导密集的车流。但由于人员不足,W 市市长决定只在最需要安排人员的路口安排人员。具体来说,W 市的交通网络十分简单,由 n 个交叉路口和 n−1 条街道构成,交叉路口路口编号依次为 0,1,?,n−1 。任意一条街道连接两个交叉路口,且任意两个交叉路口间都存在一条路径互相连接。 经过长期调查,结果显示,如果一个交叉路口位于 W 市交通网最长路径上,那么这个路口必定拥挤不堪。所谓最长路径,定义为某条路径 p=(v1,v2,v3,……,vk),路径经过的路口各不相同,且城市中不存在长度大于 k 的路径,因此最长路径可能不唯一。因此 W 市市长想知道哪些路口位于城市交通网的最长路径上。 |
输入 |
第一行一个整数 n;之后 n−1 行每行两个整数 u,v,表示 u 和 v 的路口间存在着一条街道。 |
输出 |
包括若干行,每行包括一个整数——某个位于最长路径上的路口编号。为了确保解唯一,请将所有最长路径上的路口编号按编号顺序由小到大依次输出。 |
输入示例 |
10 0 1 0 2 0 4 0 6 0 7 1 3 2 5 4 8 6 9 |
输出示例 |
0 1 2 3 4 5 6 8 9 |
其他说明 |
数据范围:对于全部数据 1 <= n <= 2×100 000?? 。 |
看注释
#include<iostream> #include<algorithm> #include<cstring> #include<string> #include<cstdio> #include<cstdlib> #include<cmath> using namespace std; inline int rd() { int x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch==‘-‘) f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-‘0‘; return x*f; } inline void write(int x) { if(x<0) putchar(‘-‘),x=-x; if(x>9) write(x/10); putchar(x%10+‘0‘); return ; } int n; int head[400006],to[400006],nxt[400006];//数组应定要开够!!!!!!!!!! int total=0; void add(int x,int y) { total++; to[total]=y; nxt[total]=head[x]; head[x]=total; return ; } int fir[400006],sec[400006];//fir[i]存的是以i为根的最长链,sec[i]是次长链 int s1[400006],s2[400006];//分别存最长连和次长链是从那个点转移的 int ans=0;//最长链长度 int dfs(int x,int la)//x是当前点,la是他的父亲节点 { for(int e=head[x];e;e=nxt[e]) { int h=to[e]; if(h!=la) { int d=dfs(h,x)+1; if(d>fir[x]) { //注意在给最长链赋值时,要把原来最长链在的额支赋给次长链 sec[x]=fir[x]; s2[x]=s1[x]; fir[x]=d; s1[x]=h; } else if(d>sec[x]) { sec[x]=d; s2[x]=h; } } } ans=max(ans,fir[x]+sec[x]);//因为最长链和次长链从不同子树转移,所以书上最长链为两个的和 return fir[x]; } int g[400006]; void dp(int x,int la) { if(x!=0) { /* 玄学存 因为fir和sec存的是由子树转移的值 所以就忽略了一种特殊情况 例子: * | * | * / * * / * * 所以很明显,我们需要一个数组来存上面的最长链 */ if(x!=s1[la]) g[x]=max(fir[la]+1,g[la]+1);//不能从父亲节点直接转移,因为可能是fir,所以用到了s1和s2 else g[x]=max(sec[la]+1,g[la]+1); } for(int e=head[x];e;e=nxt[e]) if(to[e]!=la) dp(to[e],x); } int main() { n=rd(); for(int i=1;i<n;i++) { int x,y; x=rd(); y=rd(); add(x,y);//双向存边,因为是无向图 add(y,x); } dfs(0,0);//注意初值,下标从0开始 dp(0,0); for(int i=0;i<n;i++) if(g[i]+fir[i]==ans||fir[i]+sec[i]==ans) printf("%d\n",i);//输出节点(调了好久QAQ) return 0; }
最后喜欢的话不如来推荐,评论,关注三连。
不喜欢的话也昧着良心推荐一下吧!!!!
原文地址:https://www.cnblogs.com/WWHHTT/p/9505050.html
时间: 2024-11-08 23:11:47