关于次小生成树 详解及模板 仅kruskal

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/JiangHxin/article/details/102223985

前言

关于次小生成树 详解及模板 仅kruskal (因为kru太好写了了了 后续再补上prim
其实九月份的时候就接触了最小生成树和最短路,迷迷糊糊过了一个月,现在回头看可以发现这两种算法有很多相似的地方/思想(举个栗子:prim和dijkstra \ 次短路和次小生成树)

思路

关于次小生成树,首先求出最小生成树,然后枚举每条不在最小生成树上的边(在原本的节点上添加一个vis属性进行判断即可),并把这条边放到最小生成树上面,然后就一定会形成环,那么我们在这条环路中取出一条(除了新加入的那一条边)最长的路(这里可以用d[u][v]来维护)。最终得到的权值就是次小生成树的权值。

实现

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
using namespace std;
const int manx=200+5;
const int mamx=1e5+5;
int n,m,u,v,w,k;
int f[manx],d[manx][manx];  //d数组用来维护u到v的距离,在枚举边的时候会用到
vector<int>p[manx]; //扩展路径,path数组,缩写p
struct node{
    int u,v,w;
    bool vis;  //比常规最小生成树多了vis属性判断边是否加入最小生成树的集合
}a[mamx];
bool cmp(node a,node b)
{
    return a.w<b.w;
}
int find(int x)
{
    if(f[x]==x) return x;
    else return f[x]=find(f[x]);
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        k=0;
        scanf("%d%d",&n,&m); 
        for(int i=1;i<=n;i++){   //初始化操作,万物之父皆自己
            p[i].clear();  
            p[i].push_back(i);
            f[i]=i;
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            a[++k].u=u,a[k].v=v,a[k].w=w,a[i].vis=false;
        }
        sort(a+1,a+1+k,cmp);
        ll ans=0;
        int total=1;
        for(int i=1;i<=k;i++)
        {
            u=find(a[i].u),v=find(a[i].v);
            if(u==v) continue;
            ans+=a[i].w;
            f[u]=v; 
            a[i].vis=1; //标记进去最小生成树的集合
            total++;
            int l1=p[u].size(),l2=p[v].size(); 
            for(int j=0;j<l1;j++)
                for(int k=0;k<l2;k++)
                    d[p[u][j]][p[v][k]]=d[p[v][k]][p[u][j]]=a[i].w; //记录最小生成树中扩展路径的距离
            for(int j=0;j<l1;j++) p[v].push_back(p[u][j]); //合并路径 
            if(total==n) break;
        }
        ll res=inf; //次小生成树的集合
        for(int i=1;i<=k;i++)
            if(!a[i].vis)  //枚举每条没加入最小生成树的集合
                res=min(res,ans+a[i].w-d[a[i].u][a[i].v]); 
        //ans是最小生成树的权值,减去最小生成树中u到v这条边的权值,加上枚举的这一条边进行比较
        if(res>ans) cout<<ans<<endl;
        else cout<<"Not Unique!"<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/JiangHxin/article/details/102223985
今日推荐