您的位置:首页 > 其它

Timus OJ 1056. Computer Net

2011-09-02 21:37 246 查看
题目链接: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: