图论-非严格次小生成树

定义:

对于一个无向图G(V, E),其定义了边权为W(u, v),若T为他的一颗最小生成树,那么我们假设存在一颗生成树T1,不存在任意一颗G的生成树T2满足W(T) <= W(T2) < W(T1)(此为非严格次小生成树),那么我们就称T1为G的次小生成树。
通俗易懂地来说可以理解为权值第二小的生成树。

解题思路:

这里只讨论非严格次小生成树。
如果想要得到次小生成树,可以通过替换最小生成树中的一条边做到。当一条边插入到最小生成树的时候,一定会形成一个环。只有将这个环里的最大的边去掉,才有可能得到次小生成树!(当然不能去掉那条刚加入进去的边)。把所有未在最小生成树里的边全部按照这个方法计算一次,就可以得到次小生成树了。
可以概括为以下几个步骤:

  1. 求最小生成树。(如果最小生成树都不存在,那一定不存在次小生成树)
  2. 向最小生成树中插入边。
  3. 去掉因为步骤2形成环中的最大边

难点无非就是步骤3,如何去找到形成的环中最大的边。

prim:

由于prim算法是集点算法,所以在求最小生成树的时候只需要去记录每两个点之间的最大边长。
关于如何去记录每两个点之间的最大边长

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define ll long long
#define MT(a,b) memset(a,b,sizeof(a))
const int maxn=1E5+5;
const int ONF=-0x3f3f3f3f;
const int INF=0x3f3f3f3f;
int n,m;
int mp[105][105];
bool vis[105][105];
int mst[105];
int lowcost[105];
int max_cost[105][105];
int prim(int start){
    int ans=0,tmp,min_num;
    for (int i=1;i<=n;i++){
        lowcost[i]=mp[i][start];
        mst[i]=start;
    }
    MT(vis,false);
    MT(max_cost,0);
    mst[start]=-1;
    for (int i=1;i<n;i++){
        min_num=INF;
        tmp=-1;
        for (int j=1;j<=n;j++){
            if (min_num>lowcost[j]&&mst[j]!=-1){
                min_num=lowcost[j];
                tmp=j;
            }
        }
        if (tmp==-1) return -1;
        ans+=lowcost[tmp];
        vis[tmp][mst[tmp]]=vis[mst[tmp]][tmp]= true;
        mst[tmp]=-1;
        for (int j=1;j<=n;j++){
            if (mst[j]==-1&&j!=tmp) max_cost[j][tmp]=max_cost[tmp][j]=max(max_cost[j][mst[tmp]],lowcost[tmp]);
            if (lowcost[j]>mp[j][tmp]&&mst[j]!=-1){
                mst[j]=tmp;
                lowcost[j]=mp[j][tmp];
            }
        }
    }
    return ans;
}

int second_mst(int MST){
    int ans=INF;
    for (int i=1;i<=n;i++)
        for (int j=i+1;j<=n;j++)
            if (mp[i][j]!=INF&&vis[i][j]== false)
                ans=min(ans,MST-max_cost[i][j]+mp[i][j]);
    return ans;
}
int main (){
    int t;
    scanf ("%d",&t);
    while (t--){
        int a,b,c;
        MT(mp,INF);
        scanf ("%d%d",&n,&m);
        for (int i=1;i<=m;i++){
            scanf ("%d%d%d",&a,&b,&c);
            mp[a][b]=mp[b][a]=c;
        }
        int tmp1=prim(1);
        int tmp2=second_mst(tmp1);
        if (tmp1==tmp2) printf("Not Unique!\n");
        else printf("%d\n",tmp1);
    }
    return 0;
}
发布了33 篇原创文章 · 获赞 15 · 访问量 906

猜你喜欢

转载自blog.csdn.net/weixin_43925900/article/details/102972780