修路方案
时间限制: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
题解:此题的边数较多,不能使用邻接矩阵存边,即不能使用prime算法,用 kruskal算法,先找到一个最小生成树记录下构成它的所有的边,然后再遍历这颗树的边一条条删去查找
是否有另一颗最小树#include<stdio.h> #include<string.h> #include<queue> #include<cstdio> #include<string> #include<math.h> #include<algorithm> #define LL long long #define PI atan(1.0)*4 #define DD double #define MAX 200100 #define mod 100 #define dian 1.000000011 #define INF 0x3f3f3f using namespace std; int set[MAX]; int a[510],b[510],c[510]; struct record { int beg; int end; int ju; //两村庄之间距离 }s[MAX]; int find(int fa) //寻找根节点 { int ch=fa; int t; while(fa!=set[fa]) fa=set[fa]; while(ch!=fa) { t=set[ch]; set[ch]=fa; ch=t; } return fa; } void mix(int x,int y) //合并已有村庄 { int fx,fy; fx=find(x); fy=find(y); if(fx!=fy) set[fx]=fy; } bool cmp(record a,record b) { return a.ju<b.ju; //将两村庄之间距离从小到大排列 } int main() { int n,m,j,i,sum,l,t,k; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(j=1;j<=n;j++) set[j]=j; for(i=0;i<m;i++) scanf("%d%d%d",&s[i].beg,&s[i].end,&s[i].ju); sort(s,s+m,cmp); sum=0;k=0; for(i=0;i<m;i++) { if(find(s[i].beg)!=find(s[i].end)) //选择最短路径 { a[k++]=i; mix(s[i].beg,s[i].end); sum+=s[i].ju; } } int flag=0; int ant=0;int op; for(i=0;i<k;i++) { for(j=1;j<=n;j++) set[j]=j; op=s[a[i]].ju; s[a[i]].ju=INF; sort(s,s+n,cmp); int ans=0; for(j=0;j<m;j++) { if(find(s[j].beg)!=find(s[j].end)) //选择最短路径 { mix(s[j].beg,s[j].end); ans+=s[j].ju; } } s[m-1].ju=op;//这里注意将删去的边还原 sort(s,s+n,cmp); if(ans==sum) { flag=1; break; } } if(flag) printf("Yes "); else printf("No "); } return 0; }