次小生成树Kruskalprim

Posted mekakucityactor

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了次小生成树Kruskalprim相关的知识,希望对你有一定的参考价值。

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

   通常次小生成树是使用Prim算法进行实现的,因为可以在Prim算法松弛的同时求得最小生成树上任意两点之间的最长边。但是利用Kruskal算法却没办法在松弛的同时求得。

    所以我们就要在Kruskal求完最短路后,对于每个顶点bfs一次,得到树上任意两点的最长边。之后求可以像之前一样枚举不在树上的边,代替找最小值了。

    两种方法的时间杂度是一样的,但Kruskal的实现代码回长非常多,不过Kruskal的实现可以处理Prim难以处理的重边。

一、Kruskal模板

  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                 que.push(v);
 83             }
 84         }
 85     }
 86 }
 87 
 88 int main()
 89 {
 90     int T_T;
 91     scanf("%d",&T_T);
 92     for(int cas=1;cas<=T_T;++cas)
 93     {
 94         printf("Case #%d : ",cas);
 95         scanf("%d%d",&V,&E);
 96         init();
 97         for(int i=0;i<E;++i)
 98             scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].cost);
 99         sort(edge,edge+E);
100         int res=0;
101         for(int i=0;i<E;++i)
102             if(unite(edge[i].from,edge[i].to))
103             {
104                 res+=edge[i].cost;
105                 used[i]=true;
106                 G[edge[i].from].push_back(make_pair(edge[i].to,edge[i].cost));
107                 G[edge[i].to].push_back(make_pair(edge[i].from,edge[i].cost));
108             }
109         bool ok=true;
110         for(int i=2;i<=V;++i)
111             if(findfather(i)!=findfather(1))
112             {
113                 ok=false;
114                 break;
115             }
116         if(!ok)//不联通
117         {
118             puts("No way");
119             continue;
120         }
121         if(E==V-1)//生成树唯一
122         {
123             puts("No second way");
124             continue;
125         }
126         for(int i=1;i<=V;++i)
127             bfs(i);
128         int ans=INF;
129         for(int i=0;i<E;++i)
130             if(!used[i])
131                 ans=min(ans,res-the_max[edge[i].from][edge[i].to]+edge[i].cost);
132         printf("%d
",ans);
133     }
134     
135     return 0;
136 }

二、prim模板

 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
",ans,ans1);
88     }
89     return 0;
90 }

 

以上是关于次小生成树Kruskalprim的主要内容,如果未能解决你的问题,请参考以下文章

次小生成树

P4180 模板严格次小生成树[BJWC2010](严格次小生成树)

次小生成树

次小生成树

poj1679次小生成树入门题

次小生成树