1. 程式人生 > >【POJ1679】The Unique MST

【POJ1679】The Unique MST

最短 存在 cmp esp pan 標記 scanf iostream 退出

  1 //ver1: Kruskal+暴力枚舉刪除邊
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<algorithm>
  5 using namespace std;
  6 int t,n,m,first;
  7 int a,ok,minx,p[101];
  8 struct edge{
  9     int v1,v2,d,v;  //v標記MST中的每一條邊 
 10 }e[10001];
 11 int findp(int x){
 12     return x==p[x]?x:p[x]=findp(p[x]);
13 } 14 int cmp(edge a,edge b){ 15 return a.d<b.d; 16 } 17 void init(){ 18 cin>>n>>m; 19 ok=1;first=1; 20 for(int i=0;i<m;i++){ 21 cin>>e[i].v1>>e[i].v2>>e[i].d; 22 e[i].v=0; 23 } 24 sort(e,e+m,cmp); 25 } 26 int Kruskal(){
27 for(int i=1;i<=n;i++) 28 p[i]=i; 29 a=n; int sum=0; 30 for(int i=0;i<m;i++){ 31 int p1=findp(e[i].v1),p2=findp(e[i].v2); 32 if(p1!=p2){ 33 sum+=e[i].d; 34 a--; 35 p[p1]=p2; 36 if(first) e[i].v=1; //邊i屬於MST
37 } 38 if(a==1) break; 39 } 40 if(a==1) return sum; 41 return -1; 42 } 43 int main(){ 44 cin>>t; 45 while(t--){ 46 init(); 47 minx=Kruskal(); //求MST 48 first=0; //註意MST已經求過了 49 for(int i=0;i<m;i++){ 50 if(e[i].v){ //刪除MST中的一條邊,再添加一條邊形成連通圖 51 int t=e[i].v1; //把這條件的兩個點變成一個點,從而在下面的Kruskal中不會再選擇這條邊 52 e[i].v1=e[i].v2; 53 int sum=Kruskal(); 54 if(sum==minx) {ok=0;break;} 55 e[i].v1=t; 56 } 57 } 58 if(ok) cout<<minx<<endl; 59 else cout<<"Not Unique!\n"; 60 } 61 } 62 //ver2:Kruskal+判斷是否存在權值相等且連接的等價集合相同 63 #include<cstdio> 64 #include<iostream> 65 #include<algorithm> 66 using namespace std; 67 int t,n,m,a,minx,ok,p[101]; 68 struct edge{ 69 int x,y,w; 70 }e[10001]; 71 int cmp(edge a,edge b){ 72 return a.w<b.w; 73 } 74 int findp(int x){ 75 return x==p[x]?x:p[x]=findp(p[x]); 76 } 77 void init(){ 78 minx=0;ok=1; 79 scanf("%d%d",&n,&m); a=n; 80 for(int i=1;i<=n;i++) p[i]=i; 81 for(int i=0;i<m;i++) 82 scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w); 83 sort(e,e+m,cmp); 84 } 85 void Kruskal(){ 86 for(int i=0;i<m;i++){ 87 int p1=findp(e[i].x),p2=findp(e[i].y); 88 if(p1!=p2){ 89 for(int j=i+1;j<m;j++) 90 if(e[i].w==e[j].w){ 91 //判斷鏈接的是否是相同的集合 92 int p3=findp(e[j].x),p4=findp(e[j].y); 93 if(p3==p1&&p4==p2||p3==p2&&p4==p1){ 94 ok=0; 95 return; 96 } 97 } 98 else break;//由於e[]是有序的,發現權值不同,立即退出循環 99 p[p1]=p2; 100 minx+=e[i].w; 101 a--; 102 } 103 if(a==1) break; 104 } 105 } 106 int main() 107 { 108 scanf("%d",&t); 109 while(t--){ 110 init(); 111 Kruskal(); 112 if(ok) printf("%d\n",minx); 113 else printf("Not Unique!\n"); 114 } 115 } 116 //ver3: 可以前後求兩次MST,在權值相同的情況下,第一次邊編號小的優先選,第二次邊編號大的優先選, 117 //判斷兩次MST是否相同即可(一是最短路徑和是否相等,二是所有的邊是否相同)

判斷最小生成樹是否唯一

【POJ1679】The Unique MST