题目118 修路方案(NYOJ)

修路方案

时间限制:3000 ms  |  内存限制:65535 KB

难度:5

描述

南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路。

现在已经知道哪些城市之间可以修路,如果修路,花费是多少。

现在,军师小工已经找到了一种修路的方案,能够使各个城市都联通起来,而且花费最少。

但是,南将军说,这个修路方案所拼成的图案很不吉利,想让小工计算一下是否存在另外一种方案花费和刚才的方案一样,现在你来帮小工写一个程序算一下吧。

输入

第一行输入一个整数T(1<T<20),表示测试数据的组数
每组测试数据的第一行是两个整数V,E,(3<V<500,10<E<200000)分别表示城市的个数和城市之间路的条数。数据保证所有的城市都有路相连。
随后的E行,每行有三个数字A B L,表示A号城市与B号城市之间修路花费为L。

输出

对于每组测试数据输出Yes或No(如果存在两种以上的最小花费方案则输出Yes,如果最小花费的方案只有一种,则输出No)

样例输入

2
3 3
1 2 1
2 3 2
3 1 3
4 4
1 2 2
2 3 2
3 4 2
4 1 2

样例输出

No
Yes

来源

POJ题目改编

上传者

张云聪

题目链接:题目118 修路方案

问题分析:通过算法一求解

程序说明:用Kruskal算法实现算法一

AC的C++代码:

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

int pre[505];
void init(int n)
{
	for(int i=0;i<=n;i++)
	  pre[i]=i;
}

int find(int x)
{
	int r=x;
	while(r!=pre[r])
	  r=pre[r];
	//路径压缩 
	while(x!=pre[x]){
		int i=pre[x];
		pre[x]=r;
		x=i;
	}
	return r;
}

bool join(int x,int y)
{
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy){//采用值大为祖先 
		if(fx>fy){
			int temp=fx;
			fx=fy;
			fy=temp;
		}
		pre[fx]=fy;
		return true;
	}
	return false;
}

struct Edge{//边 
	int u,v,w;
	int vis;// 1 加入了最小生成树 0没加入最小生成树 
	bool operator<(const Edge &a)const
	{
		return w<a.w;
	}
}edge[200005];

int main()
{
	int t,v,e,a,b,l;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&v,&e);
		init(v);
		for(int i=0;i<e;i++){
			scanf("%d%d%d",&a,&b,&l);
			edge[i].u=a,edge[i].v=b,edge[i].w=l,edge[i].vis=0;
		}
		//计算最小生成树的值 
		sort(edge,edge+e);
		int mst=0,cnt=0;
		for(int i=0;i<e;i++){
			if(join(edge[i].u,edge[i].v)){
				edge[i].vis=1; 
				mst+=edge[i].w;
				cnt++;
				if(cnt==v-1)
				  break;
			}
		}
		bool flag=false;
		//采用第一种算法求次小生成树:枚举删除加入到最小生成树中的边 
		for(int i=1;i<v&&!flag;i++){
			for(int j=1;j<e;j++)
			  if(edge[j].vis==1){//这是最小生成树的一条边, 
			  	edge[j].vis=2;
			  	init(v);
			  	int ans=0,count=0;
			  	for(int k=0;k<e;k++){
			  		if(edge[k].vis==2)//不考虑这条边 
			  		  continue;
			  		if(join(edge[k].u,edge[k].v)){
			  			ans+=edge[k].w;
			  			count++;
			  			if(count==v-1)
			  			  break;
					  }
				  }
			  	if(ans==mst){
			  		flag=true;
			  		break;
				  }
				  edge[j].vis=1;//还原 
			  } 
		}
		if(flag)
		  printf("Yes\n");
		else
		  printf("No\n"); 
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/SongBai1997/article/details/81382735
118