【次小生成樹】【Kruskal】【prim】【轉】

原博客出處:https://blog.csdn.net/yasola/article/details/74276255ios

   一般次小生成樹是使用Prim算法進行實現的,由於能夠在Prim算法鬆弛的同時求得最小生成樹上任意兩點之間的最長邊。可是利用Kruskal算法卻沒辦法在鬆弛的同時求得。c++

    因此咱們就要在Kruskal求完最短路後,對於每一個頂點bfs一次,獲得樹上任意兩點的最長邊。以後求能夠像以前同樣枚舉不在樹上的邊,代替找最小值了。算法

    兩種方法的時間雜度是同樣的,但Kruskal的實現代碼回長很是多,不過Kruskal的實現能夠處理Prim難以處理的重邊。spa

1、Kruskal模板.net

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cmath>
 6 #include <vector>
 7 #include <queue>
 8 using namespace std;  9 #define INF 0x3f3f3f3f
 10 #define fi first
 11 #define se second
 12 #define mem(a,b) memset((a),(b),sizeof(a))
 13 
 14 const int MAXV=100+3;  15 const int MAXE=200+3;  16 
 17 struct Edge  18 {  19     int from,to,cost;  20     Edge(int f=0,int t=0,int c=0):from(f),to(t),cost(c){}  21     bool operator<(const Edge &other)const
 22  {  23         return cost<other.cost;  24  }  25 }edge[MAXE];  26 
 27 int V,E,par[MAXV],high[MAXV],the_max[MAXV][MAXV];  28 bool used[MAXE];//邊是否使用的標記
 29 bool vis[MAXV];  30 vector<pair<int,int> > G[MAXV];//最小生成樹
 31 
 32 void init()//初始化
 33 {  34     for(int i=1;i<=E;++i)  35         used[i]=false;  36     for(int i=1;i<=V;++i)  37  {  38         par[i]=i;  39         high[i]=0;  40  G[i].clear();  41  }  42 }  43 
 44 int findfather(int x)  45 {  46     return par[x]=par[x]==x?x:findfather(par[x]);  47 }  48 
 49 bool unite(int a,int b)  50 {  51     int fa=findfather(a),fb=findfather(b);  52     if(fa==fb)  53         return false;  54     if(high[fa]>high[fb])  55         par[fb]=fa;  56     else
 57  {  58         par[fa]=fb;  59         if(high[fa]==high[fb])  60             ++high[fb];  61  }  62     return true;  63 }  64 
 65 void bfs(int s)  66 {  67     mem(vis,0);  68     vis[s]=true;  69     the_max[s][s]=0;  70     queue<int> que;  71  que.push(s);  72     while(!que.empty())  73  {  74         int u=que.front(); que.pop();  75         for(int i=0;i<G[u].size();++i)  76  {  77             int v=G[u][i].fi;  78             if(!vis[v])  79  {  80                 vis[v]=true;  81                 the_max[s][v]=max(the_max[s][u],G[u][i].se);  82                 the_max[v][s]=the_max[s][v];  83  que.push(v);  84  }  85  }  86  }  87 }  88 
 89 int main()  90 {  91     int T_T;  92     scanf("%d",&T_T);  93     for(int cas=1;cas<=T_T;++cas)  94  {  95         printf("Case #%d : ",cas);  96         scanf("%d%d",&V,&E);  97  init();  98         for(int i=0;i<E;++i)  99             scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].cost); 100         sort(edge,edge+E); 101         int res=0; 102         for(int i=0;i<E;++i) 103             if(unite(edge[i].from,edge[i].to)) 104  { 105                 res+=edge[i].cost; 106                 used[i]=true; 107                 G[edge[i].from].push_back(make_pair(edge[i].to,edge[i].cost)); 108                 G[edge[i].to].push_back(make_pair(edge[i].from,edge[i].cost)); 109  } 110         bool ok=true; 111         for(int i=2;i<=V;++i) 112             if(findfather(i)!=findfather(1)) 113  { 114                 ok=false; 115                 break; 116  } 117         if(!ok)//不聯通
118  { 119             puts("No way"); 120             continue; 121  } 122         if(E==V-1)//生成樹惟一
123  { 124             puts("No second way"); 125             continue; 126  } 127         for(int i=1;i<=V;++i) 128  bfs(i); 129         int ans=INF; 130         for(int i=0;i<E;++i) 131             if(!used[i]) 132                 ans=min(ans,res-the_max[edge[i].from][edge[i].to]+edge[i].cost); 133         printf("%d\n",ans); 134  } 135     
136     return 0; 137 }

 

2、prim模板code

 1 #include<bits/stdc++.h>
 2 using namespace std;  3 const int inf=0x3f3f3f3f;  4 const int maxn=100+10;  5 bool link[maxn][maxn],vis[maxn];  6 int w[maxn][maxn],lowc[maxn],pre[maxn],Max[maxn][maxn];  7 int n,m;  8 int prim()  9 { 10     int i,j,p,k; 11     int minc,res=0; 12     memset(vis,false,sizeof(vis)); 13     memset(pre,0,sizeof(pre)); 14     memset(Max,0,sizeof(Max)); 15     vis[1]=true,pre[1]=1; 16     for(i=2; i<=n; i++) //初始化
17  { 18         lowc[i]=w[1][i]; 19         pre[i]=1; 20  } 21     for(i=2; i<=n; i++) //prim
22  { 23         minc=inf,p=-1; 24         for(j=1; j<=n; j++) 25  { 26             if(!vis[j]&&lowc[j]<minc) 27  { 28                 minc=lowc[j]; 29                 p=j; 30  } 31  } 32         vis[p]=true; 33         res+=minc;//最小生成樹加權值
34         Max[pre[p]][p]=minc;//直接相連的兩點最大權值就是邊權值自己
35         link[pre[p]][p]=true;//將這兩條邊標記爲最小生成樹的邊
36         link[p][pre[p]]=true; 37         for(k=1; k<=n; k++) 38             Max[k][p]=max(Max[pre[p]][p],Max[k][p]);//非直接相連的最大權值須要不斷更新
39         for(j=1; j<=n; j++) 40             if(!vis[j]&&lowc[j]>w[p][j]) 41  { 42                 lowc[j]=w[p][j]; 43                 pre[j]=p; 44  } 45 
46  } 47     return res; 48 } 49 int main() 50 { 51 // freopen("in.txt","r",stdin); 52 // freopen("out.txt","w",stdout);
53     int s,e,t,ans,ans1; 54 
55     while(~scanf("%d%d",&n,&m)) 56  { 57         int i,j; 58          bool ok=true;//是否惟一最小生成樹的標誌
59         for(i=1; i<=n; i++) 60             for(j=1; j<=n; j++) 61                 w[i][j]=inf; 62         memset(link,false,sizeof(link)); 63         for(i=1; i<=m; i++) 64  { 65             scanf("%d%d%d",&s,&e,&t); 66             w[s][e]=t; 67             w[e][s]=t; 68  } 69         ans=prim();//最小生成樹的權值
70         for(i=1; i<=n; i++) 71  { 72             for(j=i+1; j<=n; j++) 73  { 74                 if(w[i][j]!=inf&&!link[i][j]) 75  { 76                     ans1=ans+w[i][j]-Max[i][j];//ans1次小生成樹的權值
77  } 78                 if(ans1==ans) 79  { 80                     ok=0; 81                     break; 82  } 83  } 84             if(!ok) 85                 break; 86  } 87         printf("ans=%d ans1=%d\n",ans,ans1); 88  } 89     return 0; 90 }
相關文章
相關標籤/搜索