【HDU】-4514-湫湫系列故事——设计风景线(树的直径&&并查集)

本文介绍了一个关于设计经典观光线路的问题,探讨如何利用已知的位置和路线设计环形风景线,若无法形成环,则寻找最长路径。通过算法实现风景线的设计,并给出具体实现代码。

湫湫系列故事——设计风景线

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 4288    Accepted Submission(s): 755


Problem Description
  随着杭州西湖的知名度的进一步提升,园林规划专家湫湫希望设计出一条新的经典观光线路,根据老板马小腾的指示,新的风景线最好能建成环形,如果没有条件建成环形,那就建的越长越好。
  现在已经勘探确定了n个位置可以用来建设,在它们之间也勘探确定了m条可以设计的路线以及他们的长度。请问是否能够建成环形的风景线?如果不能,风景线最长能够达到多少?
  其中,可以兴建的路线均是双向的,他们之间的长度均大于0。
 

Input
  测试数据有多组,每组测试数据的第一行有两个数字n, m,其含义参见题目描述;
  接下去m行,每行3个数字u v w,分别代表这条线路的起点,终点和长度。

  [Technical Specification]
  1. n<=100000 
  2. m <= 1000000
  3. 1<= u, v <= n 
  4. w <= 1000
 

Output
  对于每组测试数据,如果能够建成环形(并不需要连接上去全部的风景点),那么输出YES,否则输出最长的长度,每组数据输出一行。
 

Sample Input
3 3 1 2 1 2 3 1 3 1 1
 

Sample Output
YES
 

题解:1,判断是否成环。2,不成环注意树可能不止一棵(根节点不唯一),找到最大的直径


#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
vector<int> link[100010];
vector<int> va[100010];
bool vis[100010];
int dis[100010];
int n,m;
int f[100010]; 
void init()
{
	for(int i=1;i<=n;i++)				//初始化 
	{
		link[i].clear();
		va[i].clear();
		f[i]=i;
	}
}
int find(int x)
{
	if(x!=f[x])
		f[x]=find(f[x]);
	return f[x];
}
bool join(int x,int y)
{
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy)
	{
		f[fx]=fy;
		return true;
	}
	return false;
}
int bfs(int x)
{
	int ans;						//最远的点 
	int maxx=0;						//距离 
	memset(vis,false,sizeof(vis));
	memset(dis,0,sizeof(dis));
	queue<int> q;
	dis[x]=0;
	q.push(x);
	vis[x]=true;
	while(!q.empty())
	{
		int st=q.front();
		q.pop();
		for(int i=0;i<link[st].size();i++)
		{
			if(!vis[link[st][i]])				//没有被访问 
			{
				q.push(link[st][i]);
				dis[link[st][i]]=dis[st]+va[st][i];		//到当前点的距离等于到父节点的距离加父节点到他的距离 
				if(maxx<dis[link[st][i]])
				{
					maxx=dis[link[st][i]];				//更新最大距离 
					ans=link[st][i];
				}
				vis[link[st][i]]=true;					//标记 
			}
		}
	}
	return ans;
}
int main()
{
	while(~scanf("%d %d",&n,&m))
	{
		init();
		bool circle=true;
		int a,b,c;
		for(int i=1;i<=m;i++)
		{
			scanf("%d %d %d",&a,&b,&c);
			link[a].push_back(b);
			va[a].push_back(c);
			link[b].push_back(a);
			va[b].push_back(c);
			if(!join(a,b))
				circle=false;			//成环 
		}
		if(!circle)
		{
			printf("YES\n");
			continue;
		}
		int maxx=0;
		for(int i=1;i<=n;i++)
		{
			if(f[i]==i)
			{
				int tt=bfs(i);				//根节点可能不止一个,所以取直径最长的 
				int ans=bfs(tt);
				maxx=max(maxx,dis[ans]);
			}
		}
		printf("%d\n",maxx);
	} 
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值