• 【次小生成树】【Kruskal】【prim】【转】


    原博客出处: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                 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
    ",ans);
    134     }
    135     
    136     return 0;
    137 }

    二、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 }
  • 相关阅读:
    POJ 3211 (分组01背包) Washing Clothes
    CodeForces 489D Unbearable Controversy of Being
    CodeForces 489C (贪心) Given Length and Sum of Digits...
    CodeForces 489B (贪心 或 最大匹配) BerSU Ball
    CodeForces 489A (瞎搞) SwapSort
    CodeForces 474.D Flowers
    UVa 1252 (状压DP + 记忆化搜索) Twenty Questions
    UVa 10817 (状压DP + 记忆化搜索) Headmaster's Headache
    【读书笔记】莫比乌斯函数与莫比乌斯反演
    UVa 11437 (梅涅劳斯定理) Triangle Fun
  • 原文地址:https://www.cnblogs.com/MekakuCityActor/p/9154947.html
Copyright © 2020-2023  润新知