裸
1.
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; struct node { int x, y, dis; int flag; bool operator<(const node a) const { return dis < a.dis; } } a[200010]; int fa[555], n; int kruskal(int num, int m) { int i, j, k; int ans = 0, cnt = 1; for (i = 0; i<m; i++) { if (i == num)//除去这条边之后再求一次最小生成树 continue; int x = fa[a[i].x]; int y = fa[a[i].y]; if (x != y) { ans += a[i].dis; cnt++; fa[y] = x; for (j = 0; j <= n; j++) if (fa[j] == y) fa[j] = x; } } if (cnt != n) return -1; else return ans; } int main() { int m, i, j, t, sum, ans, cnt; scanf("%d", &t); while (t--) { scanf("%d%d", &n, &m); for (i = 0; i <= n; i++) fa[i] = i; for (i = 0; i<m; i++) { scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].dis); a[i].flag = 0; } sort(a, a + m); cnt = 1; ans = 0; for (int i = 0; i < m; ++i) { int x = fa[a[i].x]; int y = fa[a[i].y]; if (x != y) { a[i].flag = 1; ans += a[i].dis; cnt++; fa[y] = x; for (int j = 0; j <= n; ++j) //路径压缩 if (fa[j] == y) fa[j] = x; } } int flag = 0; for (i = 0; i<m; i++) { if (a[i].flag == 0) continue; //枚举去掉每一天最小生成树的边 for (int j = 0; j <= n; ++j) //重新计算最小生成树 fa[j] = j; sum = kruskal(i, m); if (sum == ans) { //判断是否唯一 flag = 1; break; } } if (flag) printf("Yes "); else printf("No "); } return 0; }
2.
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string> 6 #include<queue> 7 #include<algorithm> 8 #include<map> 9 #include<iomanip> 10 #include<climits> 11 #include<string.h> 12 #include<cmath> 13 #include<stdlib.h> 14 #include<vector> 15 #define INF 1e7 16 #define MAXN 100010 17 #define maxn 555 18 #define Mod 1000007 19 #define N 1010 20 #define MAX 0x0fffffff 21 #define MIN -0x0fffffff 22 using namespace std; 23 typedef long long LL; 24 25 int T; 26 int G[maxn][maxn], maxlen[maxn][maxn],dis[maxn],pre[maxn]; 27 bool vis[maxn]; 28 int n, m; 29 int u, v, w; 30 int prim() 31 { 32 int min, pos; 33 memset(vis, 0, sizeof(vis)); 34 for (int i = 1; i <= n; ++i) { 35 dis[i] = G[1][i]; 36 pre[i] = 1; 37 } 38 vis[1] = 1; 39 for (int i = 1; i < n; ++i) { 40 min = MAX; 41 for (int j = 1; j <= n; ++j) { 42 if (!vis[j] && dis[j] < min) { 43 pos = j; 44 min = dis[j]; 45 } 46 } 47 int pr = pre[pos]; 48 maxlen[pos][pr] = maxlen[pr][pos] = G[pos][pr]; 49 for (int j = 1; j <= n; ++j) 50 if (vis[j]) 51 maxlen[j][pos] = maxlen[pos][j] = max(maxlen[j][pr], maxlen[pos][pr]); 52 vis[pos] = 1; 53 for (int j = 1; j <= n; ++j) { 54 if (!vis[j] && dis[j] > G[j][pos]) { 55 dis[j] = G[j][pos]; 56 pre[j] = pos; 57 } 58 } 59 } 60 for (int i = 1; i < n; ++i) 61 for (int j = i + 1; j <= n; ++j) { 62 if (pre[i] == j || pre[j] == i) continue; 63 else if (maxlen[i][j] == G[i][j]) return 1; 64 } 65 return 0; 66 } 67 68 void process() 69 { 70 scanf("%d%d", &n, &m); 71 for (int i = 0; i <= n; ++i) 72 for (int j = 0; j <= n; ++j) { 73 G[i][j] = MAX; 74 maxlen[i][j] = MIN; 75 } 76 for (int j = 1; j <= m; ++j){ 77 scanf("%d%d%d", &u, &v, &w); 78 G[u][v] = G[v][u] = w; 79 } 80 if (prim()) puts("Yes"); 81 else puts("No"); 82 } 83 84 int main() 85 { 86 scanf("%d",&T); 87 while (T--) 88 process(); 89 return 0; 90 }
3.
1 #include <iostream> 2 #include <stdio.h> 3 #include <algorithm> 4 #include <string.h> 5 using namespace std; 6 7 /* 8 * 次小生成树 9 * 求最小生成树时,用数组Max[i][j]来表示MST中i到j最大边权 10 * 求完后,直接枚举所有不在MST中的边,替换掉最大边权的边,更新答案 11 * 点的编号从0开始 12 */ 13 const int MAXN = 110; 14 const int INF = 0x3f3f3f3f; 15 bool vis[MAXN]; 16 int lowc[MAXN]; 17 int pre[MAXN]; 18 int Max[MAXN][MAXN];//Max[i][j]表示在最小生成树中从i到j的路径中的最大边权 19 bool used[MAXN][MAXN]; 20 int Prim(int cost[][MAXN], int n) 21 { 22 int ans = 0; 23 memset(vis, false, sizeof(vis)); 24 memset(Max, 0, sizeof(Max)); 25 memset(used, false, sizeof(used)); 26 vis[0] = true; 27 pre[0] = -1; 28 for (int i = 1; i<n; i++) 29 { 30 lowc[i] = cost[0][i]; 31 pre[i] = 0; 32 } 33 lowc[0] = 0; 34 for (int i = 1; i<n; i++) 35 { 36 int minc = INF; 37 int p = -1; 38 for (int j = 0; j<n; j++) 39 if (!vis[j] && minc>lowc[j]) 40 { 41 minc = lowc[j]; 42 p = j; 43 } 44 if (minc == INF)return -1; 45 ans += minc; 46 vis[p] = true; 47 used[p][pre[p]] = used[pre[p]][p] = true; 48 for (int j = 0; j<n; j++) 49 { 50 if (vis[j])Max[j][p] = Max[p][j] = max(Max[j][pre[p]], lowc[p]); 51 if (!vis[j] && lowc[j]>cost[p][j]) 52 { 53 lowc[j] = cost[p][j]; 54 pre[j] = p; 55 } 56 } 57 } 58 return ans; 59 } 60 int ans; 61 int smst(int cost[][MAXN], int n) 62 { 63 int Min = INF; 64 for (int i = 0; i<n; i++) 65 for (int j = i + 1; j<n; j++) 66 if (cost[i][j] != INF && !used[i][j]) 67 { 68 Min = min(Min, ans + cost[i][j] - Max[i][j]); 69 } 70 if (Min == INF)return -1;//不存在 71 return Min; 72 } 73 int cost[MAXN][MAXN]; 74 int main() 75 { 76 int T; 77 int n, m; 78 scanf("%d", &T); 79 while (T--) 80 { 81 scanf("%d%d", &n, &m); 82 int u, v, w; 83 for (int i = 0; i<n; i++) 84 for (int j = 0; j<n; j++) 85 { 86 if (i == j)cost[i][j] = 0; 87 else cost[i][j] = INF; 88 } 89 while (m--) 90 { 91 scanf("%d%d%d", &u, &v, &w); 92 u--; v--; 93 cost[u][v] = cost[v][u] = w; 94 } 95 ans = Prim(cost, n); 96 if (ans == -1) 97 { 98 printf("Not Unique! "); 99 continue; 100 } 101 if (ans == smst(cost, n))printf("Not Unique! "); 102 else printf("%d ", ans); 103 } 104 return 0; 105 }
另外从网上看到的次小生成树。。 第一次接触
转自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 }