【POJ 1679 The Unique MST】最小生成树
生活随笔
收集整理的這篇文章主要介紹了
【POJ 1679 The Unique MST】最小生成树
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
無向連通圖(無重邊),判斷最小生成樹是否唯一,若唯一求邊權和。
分析生成樹的生成過程,只有一個圈內出現權值相同的邊才會出現權值和相等但“異構”的生成樹。(并不一定是最小生成樹)
分析貪心策略求最小生成樹的過程(貪心地選最短的邊來擴充已加入生成樹的頂點集合U),發現只有當出現“U中兩個不同的點到V-U中同一點的距離同時為當前最短邊”時,才會出現“異構”的最小生成樹。
上圖為kruscal和prim生成過程中可能遇到的相等邊的情況,紅色和藍色的為權值相等的邊。
可以看到kruscal由于事先將所有邊按權值排序,所以在構造MST的過程中,當發現權值相同的邊時,需要遍歷之前遇到過的所有相同權值的邊來判斷是否發生“爭搶同一點”的情況,若發現即可判定存在“異構”最小生成樹。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 const int MAX_N=105; 6 const int MAX_M=5005; 7 8 int par[MAX_N]; 9 void init() 10 { 11 memset(par,-1,sizeof(par)); 12 } 13 int find(int x) 14 { 15 if(par[x]==-1) return x; 16 return par[x]=find(par[x]); 17 } 18 void unite(int x,int y) 19 { 20 x=find(x); 21 y=find(y); 22 if(x!=y) par[x]=y; 23 } 24 bool same(int x,int y) 25 { 26 return find(x)==find(y); 27 } 28 29 int t; 30 int n,m; 31 struct Edge 32 { 33 int u,v,w; 34 }e[MAX_M]; 35 36 bool cmp(Edge e1,Edge e2) 37 { 38 return e1.w<e2.w; 39 } 40 41 bool inter(Edge e1,Edge e2) 42 { 43 if(e1.u==e2.u||e1.u==e2.v||e1.v==e2.u||e1.v==e2.v) return true; 44 else return false; 45 } 46 47 int kruscal() 48 { 49 int ans=0; 50 init(); 51 ans+=e[0].w; 52 unite(e[0].u,e[0].v); 53 int cur_w=e[0].w; 54 for(int i=1;i<m;i++) 55 { 56 if(same(e[i].u,e[i].v)) 57 { 58 for(int j=i-1;e[j].w==e[i].w;j--) 59 { 60 if(inter(e[i],e[j]))//判兩條邊有無交點 61 { 62 ans=-1; 63 break; 64 } 65 } 66 }else 67 { 68 unite(e[i].u,e[i].v); 69 ans+=e[i].w; 70 cur_w=e[i].w; 71 } 72 } 73 return ans; 74 } 75 76 int main() 77 { 78 freopen("1679.txt","r",stdin); 79 scanf("%d",&t); 80 while(t--) 81 { 82 scanf("%d%d",&n,&m); 83 for(int i=0;i<m;i++) 84 { 85 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 86 } 87 if(n==1) {printf("0\n"); continue;} 88 sort(e,e+m,cmp); 89 int ans=kruscal(); 90 if(ans==-1) 91 printf("Not Unique!\n"); 92 else printf("%d\n",ans); 93 } 94 return 0; 95 } kruscal?
而prim由于每次都選連結U和V-U的邊,所以不會遇到kruscal那樣藍色的可能誤判的邊(我開始就WA在這里),因此只需在加入一個新點更新其他點的mincost時判斷有沒有和mincost值相等的另一條邊的即可。
1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <queue> 5 using namespace std; 6 const int MAX_N=105; 7 const int MAX_M=5005; 8 const int INF=100000; 9 typedef pair<int,int> P;//cost,to 10 struct Edge 11 { 12 int to,cost; 13 Edge(){} 14 Edge(int tt,int cc):to(tt),cost(cc){} 15 }; 16 int t; 17 int n,m; 18 vector<Edge> G[MAX_N]; 19 int vis[MAX_N]; 20 int mincost[MAX_N]; 21 22 int prim() 23 { 24 int ans=0; 25 int flag=0; 26 priority_queue<P,vector<P>,greater<P> > que; 27 memset(vis,0,sizeof(vis)); 28 for(int i=1;i<=n;i++) mincost[i]=INF; 29 que.push(P(0,1)); 30 mincost[1]=0; 31 while(!que.empty()) 32 { 33 P p=que.top(); 34 que.pop(); 35 int v=p.second; 36 if(vis[v]||mincost[v]<p.first) continue; 37 vis[v]=1; 38 mincost[v]=p.first; 39 ans+=mincost[v]; 40 for(int i=0;i<G[v].size();i++) 41 { 42 int u=G[v][i].to; 43 if(!vis[u]) 44 { 45 if(mincost[u]>G[v][i].cost&&G[v][i].cost<INF) 46 { 47 mincost[u]=G[v][i].cost; 48 que.push(P(mincost[u],u)); 49 }else if(mincost[u]==G[v][i].cost)//存在到達點u權值相等且都為最小值的邊 50 { 51 flag=1; 52 break; 53 } 54 } 55 } 56 if(flag) break; 57 } 58 if(flag) ans=-1; 59 return ans; 60 } 61 int main() 62 { 63 freopen("1679.txt","r",stdin); 64 scanf("%d",&t); 65 while(t--) 66 { 67 scanf("%d%d",&n,&m); 68 for(int i=1;i<=n;i++) G[i].clear(); 69 for(int i=0;i<m;i++) 70 { 71 int u,v,w; 72 scanf("%d%d%d",&u,&v,&w); 73 G[u].push_back(Edge(v,w)); 74 G[v].push_back(Edge(u,w)); 75 } 76 if(n==1) {printf("0\n"); continue;} 77 int ans=prim(); 78 if(ans==-1) 79 printf("Not Unique!\n"); 80 else printf("%d\n",ans); 81 } 82 return 0; 83 } prim_priorityqueue?
轉載于:https://www.cnblogs.com/helenawang/p/4951720.html
總結
以上是生活随笔為你收集整理的【POJ 1679 The Unique MST】最小生成树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 模拟退火算法及其Matlab实现
- 下一篇: 《光环:无限》游戏第 4 赛季 6 月