第六周作业-A

题目描述:
实验室里原先有一台电脑(编号为1),最近氪金带师咕咕东又为实验室购置了N-1台电脑,编号为2到N。每台电脑都用网线连接到一台先前安装的电脑上。但是咕咕东担心网速太慢,他希望知道第i台电脑到其他电脑的最大网线长度,但是可怜的咕咕东在不久前刚刚遭受了宇宙射线的降智打击,请你帮帮他。
在这里插入图片描述

提示: 样例输入对应这个图,从这个图中你可以看出,距离1号电脑最远的电脑是4号电脑,他们之间的距离是3。 4号电脑与5号电脑都是距离2号电脑最远的点,故其答案是2。5号电脑距离3号电脑最远,故对于3号电脑来说它的答案是3。同样的我们可以计算出4号电脑和5号电脑的答案是4.
输入:
输入文件包含多组测试数据。对于每组测试数据,第一行一个整数N (N<=10000),接下来有N-1行,每一行两个数,对于第i行的两个数,它们表示与i号电脑连接的电脑编号以及它们之间网线的长度。网线的总长度不会超过10^9,每个数之间用一个空格隔开。
输出:
对于每组测试数据输出N行,第i行表示i号电脑的答案 (1<=i<=N).
sample:
input:
5
1 1
2 1
3 1
1 1
output:
3
2
3
4
4
题目思路:
本题最暴力的方法就是每个点都往后dfs一遍,然后求出最大距离就可以,但是本题难度容易超时,所以不能太暴力。这个题就是树的最大直径问题,最大直径就是看两个点的距离最大的点是哪两个,那么如果我们能知道最远的两个点,然后从这两个点之间遍历到目标点,这样看看谁的距离最大就是最远距离了。
当然本题是无向图,这样的话就需要插入两个方向相反的点来表示双向性

void addedge(int u,int v,int w)
{
	e[total].u=u;
	e[total].v=v;
	e[total].w=w;
	e[total].next=head[u];
	head[u]=total;
	total++;
}
			addedge(i,v,w);
			addedge(v,i,w);

那么如何求最远距离的点v1和v2,就需要dfs,dfs的操作就是对于一个图,如果没到就记录下来,然后计算经过的路径,接着往下走,这样最大路径对应的点就是我们需要的点

void dfs1(int u)
{
	f1[u]=1;
	for(int i=head[u];i!=-1;i=e[i].next)
	{
		if(!f1[e[i].v])
		{
			f1[e[i].v]=1;
			num1[e[i].v]=num1[u]+e[i].w;
			if(num1[e[i].v]>ans1)
			v1=e[i].v;
			ans1=max(ans1,num1[e[i].v]);
			dfs1(e[i].v);
		}
	}
}
void dfs2(int u)
{
	f2[u]=1;
	for(int i=head[u];i!=-1;i=e[i].next)
	{
		if(!f2[e[i].v])
		{
			f2[e[i].v]=1;
			num2[e[i].v]=num2[u]+e[i].w;
			if(num2[e[i].v]>ans2)
			v2=e[i].v;
			ans2=max(ans2,num2[e[i].v]);
			dfs2(e[i].v);
		}
	}
}
void dfs3(int u)
{
	f3[u]=1;
	for(int i=head[u];i!=-1;i=e[i].next)
	{
		if(!f3[e[i].v])
		{
			f3[e[i].v]=1;
			num3[e[i].v]=num3[u]+e[i].w;
			ans3=max(ans3,num3[e[i].v]);
			dfs3(e[i].v);
		}
	}
}

以上三个dfs都是相似的,做了一点微小的改动,第一个是1开始遍历,第二个是v1,第三个是v2,这样从v1和v2出来两个路径结果,取最大值就知道谁是最远路径了
代码如下:

#include<iostream>
using namespace std;
int v1,v2,total,ans1,ans2,ans3;
int head[10010];
int num1[10010],num2[10010],num3[10010];
bool f1[10010],f2[10010],f3[10010];
struct graph//图结构
{
	int u;
	int v;
	int w;
	int next;
}e[20020];
void addedge(int u,int v,int w)//插入边
{
	e[total].u=u;
	e[total].v=v;
	e[total].w=w;
	e[total].next=head[u];
	head[u]=total;
	total++;
}
void dfs1(int u)//遍历第一遍找谁是最大直径的一个端点
{
	f1[u]=1;
	for(int i=head[u];i!=-1;i=e[i].next)
	{
		if(!f1[e[i].v])
		{
			f1[e[i].v]=1;
			num1[e[i].v]=num1[u]+e[i].w;
			if(num1[e[i].v]>ans1)
			v1=e[i].v;
			ans1=max(ans1,num1[e[i].v]);
			dfs1(e[i].v);
		}
	}
}
void dfs2(int u)//遍地第二遍找谁是最大直径的第二个端点,同时确定第一个最大端点到所有点的距离
{
	f2[u]=1;
	for(int i=head[u];i!=-1;i=e[i].next)
	{
		if(!f2[e[i].v])
		{
			f2[e[i].v]=1;
			num2[e[i].v]=num2[u]+e[i].w;
			if(num2[e[i].v]>ans2)
			v2=e[i].v;
			ans2=max(ans2,num2[e[i].v]);
			dfs2(e[i].v);
		}
	}
}
void dfs3(int u)//遍历第三遍找第二个端点到其他点的距离
{
	f3[u]=1;
	for(int i=head[u];i!=-1;i=e[i].next)
	{
		if(!f3[e[i].v])
		{
			f3[e[i].v]=1;
			num3[e[i].v]=num3[u]+e[i].w;
			ans3=max(ans3,num3[e[i].v]);
			dfs3(e[i].v);
		}
	}
}
int main()
{
	int n;
	while(cin>>n)
	{
		for(int i=0;i<10010;i++)
		{
			num1[i]=0;
			num2[i]=0;
			num3[i]=0;
			f1[i]=0;
			f2[i]=0;
			f3[i]=0;
			head[i]=-1;
		}
		ans1=0;
		ans2=0;
		ans3=0;
		total=0;
		for(int i=2;i<=n;i++)
		{
			int v,w;
			cin>>v>>w;
			addedge(i,v,w);//无向图要插入双向
			addedge(v,i,w);
		}
		dfs1(1);
		dfs2(v1);
		dfs3(v2);
		for(int i=1;i<=n;i++)
		{
			cout<<max(num2[i],num3[i])<<endl;
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值