poj 1679 The Unique MST (判斷最小生成樹是否唯一)
阿新 • • 發佈:2019-02-07
題意:判斷最小生成樹是否唯一,
若唯一,輸出最小權值和,否則,輸出 Not Unique!
判斷最小生成樹是否唯一的思路:
1、對圖中的每一條邊,掃描其他邊,如果存在相同權值的邊,則對該邊做標記
2、然後用Kruskal演算法或Prim演算法求MST
3、求得MST後,如果該MST中未包含做了標記的邊,即可判斷MST唯一;
如果包含做了標記的邊,則依次去掉這些邊的一條邊,再求MST,
如果求得的MST權值和原來的MST的權值一樣,即可判斷MST不唯一。
個人思路是先求最小生成樹,並標記最小生成樹包含的邊,
再依次判斷是否有相同權值的邊,若存在,將最小生成樹的該條邊去掉,
重新求最小生成樹,若得到的權值與原來的最小權值和相等,則不唯一
#include<stdio.h> #include<algorithm> #include<string.h> #define INF 999999 using namespace std; int n,m,k,f[105],path[105]; struct stu { int u,v,w; }edge[10010]; int cmp(stu a,stu b) { return a.w<b.w; } int find(int x) { if(x!=f[x]) f[x]=find(f[x]); return f[x]; } int kruskal(int flag) { int i,x,y,sum=0; for(i=1;i<=n;i++) f[i]=i; k=0; for(i=1;i<=m;i++){ if(edge[i].w==INF) continue; x=find(edge[i].u); y=find(edge[i].v); if(x!=y){ sum+=edge[i].w; if(flag) path[k]=i; //第一次求最小生成樹時記錄路徑 k++; if(k==n-1) break; f[x]=y; } } if(k!=n-1) sum=-1; return sum; } int main() { int T,i,j,ans,s,t,flag,num; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); memset(edge,0,sizeof(edge)); for(i=1;i<=m;i++) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w); sort(edge+1,edge+m+1,cmp); ans=kruskal(1); flag=1; num=k; for(i=0;i<num&&flag;i++){ j=path[i]; //依次判斷是否存在與路徑相同權值的邊 if(edge[j-1].w==edge[j].w||edge[j+1].w==edge[j].w){ t=edge[j].w; edge[j].w=INF; //若存在,將其標記為極大值,表示去掉此邊,再求最小生成樹 s=kruskal(0); if(s==ans) flag=0; edge[j].w=t; //將該邊還原為原值 } } if(!flag) printf("Not Unique!\n"); else printf("%d\n",ans); } return 0; }