次小生成树(POJ1679/CDOJ1959)
POJ1679
首先求出最小生成樹,記錄權(quán)值之和為MinST。然后枚舉添加邊(u,v),加上后必形成一個環(huán),找到環(huán)上非(u,v)邊的權(quán)值最大的邊,把它刪除,計算當(dāng)前生成樹的權(quán)值之和,取所有枚舉加邊后生成樹權(quán)值之和的最小值
?
?
思路:?
最小生成樹唯一性判斷,求次小生成樹的val再與最小生成樹比較。
1.先用prim算法求出最小生成樹。并在其過程中保存加入到MST中的Max[i][j]( i 到 j 路徑中的最大邊 )?
2.對未加入MST的邊進行遍歷:從MST中去掉i j路徑中的最大邊,加入未訪問邊G[i][j],如果得到的生成樹的權(quán)值和MST的相等,則存在次小生成樹的權(quán)值=MST的權(quán)值和
CDOJ 1959
思路:這道題會出現(xiàn)重邊,用Kruskal算法處理起來比較方便。(用鄰接表方便,鄰接矩陣還要考慮同兩點之間的多條權(quán)值相同的邊。)
次小生成樹的權(quán)值如果等于最小生成樹的權(quán)值, 其替換邊只會是權(quán)值相同的邊,于是可以把權(quán)值相同邊放在一起考慮,分別判斷全部沒有合并時有多少可以合并(cnt1記錄的是可以加入集合的邊數(shù)),邊合并邊判斷有多少可以合并(cnt2記錄的是選中一條加入到集合),如果可選的大于構(gòu)成最小生成樹所需要的,那么就存在一種相同的邊權(quán)可以替換原來的,從而最小生成樹不唯一。
1 #include <bits/stdc++.h> 2 #define LL long long 3 using namespace std; 4 const int N = 2e5+6; 5 struct Node 6 { 7 int u,v; 8 LL w; 9 }G[N]; 10 11 int n,m; 12 int f[2002]; 13 int find(int x) 14 { 15 return x==f[x]?x:f[x]=find(f[x]); 16 } 17 18 bool cmp(Node & a, Node & b) 19 { 20 return a.w<b.w; 21 } 22 23 void kruskal() 24 { 25 int cnt1=0; 26 int cnt2=0; 27 for(int i=1;i<=n;i++)f[i]=i; 28 sort(G,G+m,cmp); 29 for(int i=0;i<m;) 30 { 31 int j=i; 32 while(j<m&&G[j].w==G[i].w) 33 { 34 int u = find(G[j].u); 35 int v = find(G[j].v); 36 if(u!=v)cnt1++; 37 j++; 38 } 39 j=i; 40 while(j<m&&G[j].w==G[i].w) 41 { 42 int u = find(G[j].u); 43 int v = find(G[j].v); 44 if(u!=v){ 45 cnt2++; 46 f[u]=v; 47 } 48 j++; 49 } 50 i=j; 51 if(cnt1>cnt2)break; 52 } 53 if( cnt1 > cnt2 ){ 54 printf("zin\n"); 55 }else{ 56 printf("ogisosetsuna\n"); 57 } 58 } 59 60 int main() 61 { 62 int x,y; 63 LL w; 64 cin>>n>>m; 65 for(int i=0;i<m;i++) 66 { 67 cin>>x>>y>>w; 68 G[i].u=x; 69 G[i].v=y; 70 G[i].w=w; 71 } 72 kruskal(); 73 return 0; 74 }?
轉(zhuǎn)載于:https://www.cnblogs.com/demian/p/9188918.html
總結(jié)
以上是生活随笔為你收集整理的次小生成树(POJ1679/CDOJ1959)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用 fdisk进行分区
- 下一篇: js中闭包的概念和用法