题目大意:给定一个联无向网,判断它的最小生成树是否唯一。
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 20421 | Accepted: 7183 |
Description
Input
Output
Sample Input
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
Sample Output
3 Not Unique! 1:在prim()中记录每个入树点的前缀点,在一次prim()之后对每个入树点a 遍历其它所有的入树点, 看该入树点a的入树方式是否唯一,若不唯一,则存在多个最小生成树!.<span style="font-size:18px;">#include<iostream> #include<algorithm> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<queue> #include<math.h> #include<set> #include<vector> using namespace std; #define maxn 150 #define MM 100000000 int n,m,sum; int v[maxn]; int d[maxn]; int W[maxn][maxn]; int w[maxn][maxn]; int vis[maxn]; int Vis[maxn][maxn]; int conut; void prim() { sum=0; memset(v,0,sizeof(v)); memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) d[i]=(i==1?0:MM); for(int j=1;j<=n;j++) { int x,mm=MM; for(int i=1;i<=n;i++) if(d[i]<mm && !v[i]) mm=d[x=i]; sum+=mm; v[x]=1; for(int i=1;i<=n;i++) if(d[i]>w[x][i]) { d[i]=w[x][i]; vis[i]=x; } } } int main() { int t; cin>>t; while(t--) { conut=0; int a,b,c; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) w[i][j]=MM; for(int i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); if(w[a][b]>c) w[a][b]=w[b][a]=c; } prim(); for(int i=1;i<=n;i++) { if(vis[i]) for(int j=1;j<=n;j++) if(j!=vis[i] && v[j] && w[j][i]==w[i][vis[i]]) conut=1; } if(conut) printf("Not Unique!\n"); else printf("%d\n",sum); } return 0; } </span>
******************####################################################**********************
2:逐个删边再次prim();容易想到,复杂度高O(n^4) 在每个点入树的时候用数组vis标记改点的入树“支点”。----这是 我做这题时不知道怎么处理的地方。<span style="font-size:18px;"> #include<iostream> #include<algorithm> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<queue> #include<math.h> #include<set> #include<vector> using namespace std; #define maxn 150 #define MM 100000000 int n,m,sum; int v[maxn]; int d[maxn]; int W[maxn][maxn]; int w[maxn][maxn]; int vis[maxn]; int Vis[maxn][maxn]; void prim() { sum=0; memset(v,0,sizeof(v)); memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) d[i]=(i==1?0:MM); for(int j=1;j<=n;j++) { int x,mm=MM; for(int i=1;i<=n;i++) if(d[i]<mm && !v[i]) mm=d[x=i]; sum+=mm; v[x]=1; for(int i=1;i<=n;i++) if(d[i]>w[x][i]) { d[i]=w[x][i]; vis[i]=x; // 保存入树点的入树“支点” } } } int main() { int t; cin>>t; while(t--) { int a,b,c; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) w[i][j]=MM; for(int i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); if(w[a][b]>c) w[a][b]=w[b][a]=c; } prim(); memset(Vis,0,sizeof(Vis)); for(int i=n;i>1;i--) { if(vis[i]) Vis[vis[i]][i]=Vis[i][vis[i]]=1; // 标记入树的边 } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) W[i][j]=w[i][j]; //用W数组保存各边的原始数据,Sum保存最小的距离,conut标记是否有不止一个最小生成树。 int SUM=sum,conut=0,cc=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(Vis[i][j]==1) //如果该边在第一次prim中已入树,删除该边,再次prim(); { if(conut) break; for(int ii=1;ii<=n;ii++) for(int jj=1;jj<=n;jj++) w[ii][jj]=W[ii][jj]; w[i][j]=w[j][i]=MM; prim(); if(SUM==sum) // 一旦删除边后所求最小生成树与删除边前所求相等 ----最小生成树不唯一。conut=1; { conut=1; //还可以 用conut++ 来求最小生成树的个数。 } } if(!conut) printf("%d\n",SUM); else printf("Not Unique!\n"); } return 0; }</span>
poj1679 The Unique MST,布布扣,bubuko.com
原文地址:http://blog.csdn.net/u013712847/article/details/38491575