nyoj 118 修路方案(次小生成树)

来源:互联网 发布:windowsrt软件 编辑:程序博客网 时间:2024/05/17 22:47

修路方案

时间限制: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)
样例输入
23 31 2 12 3 23 1 34 41 2 22 3 23 4 24 1 2
样例输出
NoYes
来源
POJ题目改编
上传者

张云聪

次小生成树,算法思路:
先求出最小生成树,记录值和边,然后依次每次删除这些边中的一条,用再求最小生成树
算出来的值找出最小的就是次小生成树的值。
这题只需要比较每次新建的最小生成树的值是否和原来最小生成树的值是否一样就可以了。

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std; #define inf 0x3f3f3f3fconst int M=510;const int N=210000;struct node{int s,e,w,vis;}mp[N];int x[M],n,m;bool cmp(node a,node b){return a.w<b.w;}void init(){for(int i=0; i<M; ++i)x[i] = i;}int Find(int k){if(x[k]==k) return k;x[k]=Find(x[k]);         //压缩路径 return x[k];}int LT(){//判断图是否连通 int t=Find(1);for(int i=2;i<=n;++i){if(Find(i) != t)return 0;}return 1;}int judge(int n){int sum=0;for(int i=0;i<m;++i){if(i!=n){// 删除这条边再求最小生成树 int fa=Find(mp[i].s);int fb=Find(mp[i].e);if(fa!=fb){sum+=mp[i].w;x[fb]=fa;}}}if( LT() ) return sum;return -1;}int main(){int t;int a,b,c;scanf("%d", &t);while(t--){init();scanf("%d%d",&n,&m);for(int i=0; i<m; ++i){scanf("%d%d%d",&a,&b,&c);mp[i].s = a;mp[i].e = b;mp[i].w = c;mp[i].vis=0;}int sum=0,mx=0;sort(mp,mp+m,cmp);for(int i=0; i<m; ++i){int A=Find(mp[i].s);int B=Find(mp[i].e);if(A!=B){x[B]=A;sum+=mp[i].w;mp[i].vis=1;}}int ok=0;for(int i=0; i<m; ++i){if(mp[i].vis == 1){init();//注意每次的初始化 if(judge(i) == sum){ok=1;break;}}}if(ok) printf("Yes\n");else printf("No\n");}return 0;}


0 0