裸
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 6 struct node 7 { 8 int x, y, dis; 9 int flag; 10 } a[200010]; 11 12 int cmp(node x, node y) 13 { 14 return x.dis<y.dis; 15 } 16 int father[555], n; 17 18 int kruskal(int num, int m) 19 { 20 int i, j, k; 21 int ans = 0, cnt = 1; 22 for (i = 0; i<m; i++) 23 { 24 if (i == num)//除去这条边之后再求一次最小生成树 25 continue; 26 int s1 = father[a[i].x]; 27 int s2 = father[a[i].y]; 28 if (s1 != s2) 29 { 30 ans += a[i].dis; 31 cnt++; 32 father[s2] = s1; 33 for (j = 0; j <= n; j++) 34 if (father[j] == s2) 35 father[j] = s1; 36 } 37 } 38 if (cnt != n) 39 return -1; 40 else 41 return ans; 42 } 43 44 int main() 45 { 46 int m, i, j, t, sum, ans, cnt; 47 scanf("%d", &t); 48 while (t--) 49 { 50 scanf("%d%d", &n, &m); 51 for (i = 0; i <= n; i++) 52 father[i] = i; 53 for (i = 0; i<m; i++) 54 { 55 scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].dis); 56 a[i].flag = 0; 57 } 58 sort(a, a + m, cmp); 59 cnt = 1; 60 ans = 0; 61 for (i = 0; i<m; i++) 62 { 63 int s1 = father[a[i].x]; 64 int s2 = father[a[i].y]; 65 if (s1 != s2) 66 { 67 a[i].flag = 1; 68 ans += a[i].dis; 69 cnt++; 70 father[s2] = s1; 71 for (j = 0; j <= n; j++) 72 if (father[j] == s2) 73 father[j] = s1; 74 } 75 } 76 int flag = 0; 77 for (i = 0; i<m; i++)//枚举所有原最小生成树上的边 78 { 79 if (a[i].flag == 0) 80 continue; 81 sum = 0; 82 for (j = 0; j <= n; j++)//初始化 83 father[j] = j; 84 sum = kruskal(i, m); 85 if (sum == ans)//与之前的最小生成树比较,如果相等,那么肯定不是唯一的 86 { 87 flag = 1; 88 break; 89 } 90 } 91 if (flag) 92 printf("Yes\n"); 93 else 94 printf("No\n"); 95 } 96 97 return 0; 98 }
另外从网上看到的次小生成树。。 第一次接触
转自http://blog.csdn.net/yhrun/article/details/6916489
解题思路:花费最少且任意两个城市能够相同,则说明要求最小生成树。而题目中问是否存在另外一种方案,达到
最小生成树的效果,所以可以采用次小生成树
常用的一种方法就是在求出最小生成树的基础上进行添加边
具体实现:先用prim算法求出最小生成树,并且统计任意一点到其他各点的路径上的最大边权。然后添加改生成树上没有的边(u,v),添加一条边后就会形成环,
然后删除该环中权值大二大的边(即除(u,v)之外的最大权值的边),然后再次统计此时的的费用,如果和最小生生成树的费用相同,则说明存在另外一种方案。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 #include<cstdio> 6 using namespace std; 7 #define M 501 8 int ch1[M][M]; //保存原始边 9 int ch2[M][M]; //ch2[i][j]表示i到j的路径中的最大比边 10 vector<int> s; //保存最小生成树的节点 11 int v[M]; //标记访问过的节点 12 int sum=0; 13 void prim(int m,int n) 14 { 15 s.clear();s.push_back(m);v[m]=1; 16 while(s.size()!=n) 17 { 18 int k=200000,x,y; 19 for(int i=0;i<s.size();i++) 20 { 21 int r=s[i]; 22 for(int j=1;j<=n;j++) 23 { 24 if(!v[j]&&ch1[r][j]!=-1) 25 { 26 if(k>ch1[r][j]) 27 { 28 k=ch1[r][j];x=r;y=j; 29 } 30 } 31 } 32 } 33 for(int i=0;i<s.size();i++) 34 { 35 if(ch2[s[i]][x]<ch1[x][y]) 36 {ch2[y][s[i]]=ch2[s[i]][y]=ch1[x][y];} 37 else {ch2[y][s[i]]=ch2[s[i]][y]=ch2[s[i]][x];} 38 } 39 s.push_back(y);sum+=k;v[y]=1;ch1[x][y]=-1;ch1[y][x]=-1; 40 } 41 } 42 int main() 43 { 44 int N;scanf("%d",&N); 45 while(N--) 46 { 47 int m,n;scanf("%d%d",&m,&n); 48 memset(ch1,-1,sizeof(ch1));memset(ch2,-1,sizeof(ch2));memset(v,0,sizeof(v)); 49 for(int i=0;i<n;i++) 50 { 51 int x,y,z;scanf("%d%d%d",&x,&y,&z); 52 ch1[x][y]=z;ch1[y][x]=z; 53 ch2[x][y]=z;ch2[y][x]=z; 54 } 55 prim(1,m);int flat=0; 56 for(int i=1;i<=m;i++) 57 { 58 for(int j=1;j<=m;j++) 59 { 60 if(ch1[i][j]!=-1) 61 { 62 //cout<<i<<" "<<j<<" "<<ch1[i][j]<<endl; 63 //cout<<ch2[i][j]<<endl; 64 int k=sum-ch2[i][j]+ch1[i][j]; 65 if(k==sum) 66 { 67 flat=1;break; 68 } 69 } 70 } 71 if(flat)break; 72 } 73 if(flat)cout<<"Yes"<<endl; 74 else cout<<"No"<<endl; 75 } 76 }
时间: 2024-10-10 03:29:39