当前位置: 代码迷 >> 综合 >> NYOJ - 118 - 修路方案 ( 次小生成树 )
  详细解决方案

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

热度:42   发布时间:2023-10-09 16:56:27.0

描述

南将军率领着许多部队,它们分别驻扎在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


题目大意:将N个点连通的最短路径是否唯一。

题目思路:求最短路径求出最小生成树即可,最短路是否唯一,只要判断次小生成树的值是否和最小生成树的值相等即可。求次小生成树的方法,求出最小生成树后,最小生成树中所用到的边,依此枚举取掉其中一条边所能得到的最小生成树,(例如,一共有边1,2,3,4,5。最小生成树用到边1,2,3。那么依此算出(2,3,4,5) (1,3,4,5) (1,2,4,5) 这三种情况的最小生成树。)这些最小生成树中的最小值为次小生成树,在建树完成后,要判断这n个结点是否连通。


#include<cstdio>
#include<algorithm>
#define N 505
using namespace std;
int p[N],n,m,min1,min2,T;
int vis[N*N];
struct E{int a,b,dis;int vis;
}e[N*N];bool cmp(E e1,E e2){return e1.dis<e2.dis;
}int find(int x){return p[x] == x ? x : p[x] = find(p[x]);
}int Kruscal(int u){int ans = 0;for(int i=0 ;i<m ;i++){if(u!=i){int fx = find(e[i].a);int fy = find(e[i].b);if(fx!=fy){ans += e[i].dis;p[fx] = fy;}	}}int father = find(1);for(int i=2 ;i<=n ;i++){if(find(i)!=father)ans = -1;}return ans;
}void init(){for(int i=0 ;i<=n ;i++) p[i] = i;
}int main(){scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);for(int i=0 ;i<m ;i++){scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].dis);e[i].vis = 0; }int flag = 1;min1 = min2 = 0;//求最小生成树 init();sort(e,e+m,cmp);for(int i=0 ;i<m ;i++){int fx = find(e[i].a);int fy = find(e[i].b);if(fx!=fy){e[i].vis = 1;p[fx] = fy;min1 += e[i].dis;}}//求次小生成树 for(int i=0 ;i<m ;i++){if(e[i].vis==1){init();min2 = Kruscal(i);}if(min2==min1){flag = 0;break;}}if(flag)puts("No");else	puts("Yes");}return 0;
}