判斷最小生成樹是否為一(krustra)
阿新 • • 發佈:2018-12-14
具體思路:
首先跑一遍最短路演算法,然後將使用到的邊標記一下,同時使用一個數組記錄每一個權值出現的次數,如果出現過的權值超過一次,那麼每一次標記一條標記過的邊,再去跑最短路演算法,如果去除這條邊之後的權值和未未去除的時候的權值相同,那麼這個最短生成樹就不是唯一的,否則就是唯一的。
AC程式碼:
#include<iostream> #include<string> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<stdio.h> using namespace std; # define maxn 100000+10 # define inf 0x3f3f3f3f # define ll long long int n,m,tt; int vis[maxn]; int father[maxn]; int first; struct node { int num; int fr; int to; int cost; int chu; } q[maxn]; bool cmp(node t1,node t2) { return t1.cost<t2.cost; } int Find(int t) { return t==father[t]? t: father[t]=Find(father[t]); } int krustra(int w) { for(int i=1; i<=n; i++) { father[i]=i; } int sum=0; for(int i=1; i<=tt; i++) { if(q[i].num==w)continue; int s1=Find(q[i].fr); int s2=Find(q[i].to); if(s1!=s2) { sum+=q[i].cost; father[s1]=s2; if(first==1){//第一次記錄未去掉邊的時候的所選的邊。 q[i].chu=1; } } } return sum; } int main() { int T; scanf("%d",&T); while(T--) { memset(vis,0,sizeof(vis)); scanf("%d%d",&n,&m); tt=0; int t1,t2,t3; for(int i=1; i<=m; i++) { scanf("%d%d%d",&t1,&t2,&t3); q[++tt].fr=t1; q[tt].to=t2; q[tt].cost=t3; q[tt].num=i; q[tt].chu=0; q[++tt].fr=t2; q[tt].to=t1; q[tt].cost=t3; q[tt].num=i; vis[t3]++; q[tt].chu=0;// } sort(q+1,q+tt+1,cmp); first=1; int ans=krustra(0); first=0; int flag=0; for(int i=1; i<=tt; i++) { if(vis[q[i].cost]>=2&&q[i].chu==1)//如果這條邊的權值出現過不止一次並且在最短路中出現過,那麼這條邊就成為了實驗物件。 { int temp=krustra(q[i].num); if(temp==ans) { flag=1; break; } } } if(flag==1)printf("Not Unique!\n"); else printf("%d\n",ans); } return 0; }