Timus OJ 1056. Computer Net

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1056

题目意思:题目的意思就是在一棵无权树上输出每个点到树中其他点中最长的那条路的长度。
两次DFS,第一次主要求fs即first长路(最长向下子路)和second长路(次长向下子路)第二次主要求up每个点向上走的话最长的路
所以最优解就产生在向下的最长路和向上的最长路路之间。

#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAXX=10100; struct Tree { Tree() { we=0; next=0; v=0; } int v,we,next; }; Tree tree[MAXX*2]; int head[MAXX*2],pt; int down_f[MAXX]; //向下走的first大距离 int down_s[MAXX];//向下走的second大距离 注意这里所求的最大和次大距离必须在父节点的不同分支上 int up[MAXX];//向上走的最大距离 这个很重要 int mark[MAXX];//用来标记某点v是否在其父节点的最大距离分支上 int n; void init() { pt=1; memset(head,0,sizeof(head)); memset(down_f,0,sizeof(down_f)); memset(down_s,0,sizeof(down_s)); memset(up,0,sizeof(up)); } int max(int a,int b) { return a>b?a:b; } void adde(int x,int y,int we) { tree[pt].we=we; tree[pt].v=y; tree[pt].next=head[x]; head[x]=pt++; } void DFS_fs(int root,int pre) { int v; for(int i=head[root];i;i=tree[i].next){ v=tree[i].v; if(v==pre)continue; DFS_fs(v,root); if(down_f[root]<down_f[v]+tree[i].we)//这里就是注意把<和=别放一块,因为只有小于的时候才会改变最长路径所在的子树 { //而当等于的时候只改变次长子路长度,对最长子路无影响, 这里wa了三次 down_s[root]=down_f[root]; down_f[root]=down_f[v]+tree[i].we; mark[root]=v; }else if(down_f[root]==down_f[v]+tree[i].we) { down_s[root]=down_f[root]; }else { down_s[root]=max(down_f[v]+tree[i].we,down_s[root]);//当v的最长子树+他到root的权值小于root的最长子路时不要忘掉判断这个是否是次长路 } } } void DFS_up(int root,int pre)//从根往下,很好理解为什么这么处理因为子都要用到父的状态 { int v; for(int i=head[root];i;i=tree[i].next) { v=tree[i].v; if(v==pre)continue; if(v==mark[root]){//这里是判断如果v在root的最长路径所在的那棵子树时 up[v]=max(up[root],down_s[root])+tree[i].we;//最长路和该点重合所以从root往上走还是root往下走次长路中选择较长的加上父子之间的1条边就完了非常显然一看就能懂包括下面 }else{//当不再时则可以从root往上走还是root往下走最长路选择较长的加上父子之间一条边就完了 up[v]=max(up[root],down_f[root])+tree[i].we; } DFS_up(v,root); } } void solve(int root) { DFS_fs(root,-1); up[1]=0; DFS_up(root,-1); } int main() { int son,i,min=900000009,s=0,temp; scanf("%d",&n); init(); for(i=2;i<=n;i++) { scanf("%d",&son); adde(i,son,1);//这里如果是有权树的话,只需要把相应的权值代替这里的1就可以了 adde(son,i,1); } solve(1);//solve完后就已经处理完了,最长路只可能出现在向下走的最长路或向上走两种情况中 下面就是筛选了 for(i=1;i<=n;i++) { temp=max(down_f[i],up[i]);//最长路只可能出现在向下走的最长路或向上走两种情况中 if(temp<min){ min=temp; s=0; up[s++]=i; }else if(temp==min){ up[s++]=i; } } for(i=0;i<s;i++){ printf("%d",up[i]); if(i!=s-1)printf(" "); } printf("\n"); return 0; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值