最小生成树&次小生成树(并查集+贪心+暴力枚举)

#include<bits/stdc++.h>
using namespace std;
const int L=1e5+7;
const int inf=0x3f3f3f3f;
const int maxn=1000+7;
int father[maxn],n,m,num[maxn],nPos;//父节点(并查集),点数,边数,最小生成树点集,当前访问方位
struct node{
    int s,y,w;
}edge[L];//边集,左端点,右端点,权值
void init(){//初始化并查集
    for(int i=0;i<=n;i++)
        father[i]=i;
}
int root(int x){//并查集,构造父节点
    return father[x]==x?x:father[x]=root(father[x]);
}
void unite(int x,int y){//并查集,合并两个联通图
    x=root(x);
    y=root(y);
    if(x!=y)
        father[y]=x;
}
int alike(int x,int y){//并查集,判断是否为同一连通图
    return root(x)==root(y);
}
int secondTree(int pos)//次小生成树
{
    init();//初始化
    int sum=0,cnt=0;
    for(int i=0;i<m;i++)//对于删去边后的图进行最小生成树运算
    {
        if(cnt==n-1)
            break;
        if(i==pos)//删边
            continue;
        if(!alike(edge[i].s,edge[i].y)){
            unite(edge[i].s,edge[i].y);
            sum+=edge[i].w;
            cnt++;
        }
    }
    return cnt!=n-1?-1:sum;//判断删除边后是否能构成最小生成树
}
int cmp(node a,node b){//sort结构体排序
    return a.w<b.w;
}
int kruskal(){ //最小生成树
    init();
    sort(edge,edge+m,cmp);//对边进行权值排序
    int sum=0,cnt=0;
    for(int i=0;i<m;i++)//每次选择最小且未访问过的一条边
    {
        if(cnt==n-1)
            break;
        if(!alike(edge[i].s,edge[i].y)){
            unite(edge[i].s,edge[i].y);
            sum+=edge[i].w;
            cnt++;
            num[++nPos]=i;//记录最小生成树
        }
    }
    return cnt!=n-1?-1:sum;//判断边是否大于等于n-1,否则输出-1
}
void read(){ //读入数据
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
        scanf("%d%d%d",&edge[i].s,&edge[i].y,&edge[i].w);
}
void solve(){ //解决方案
    int Min=inf;
    nPos=0;
    int mst=kruskal(); //最小生成树值
    printf("%d\n",mst);
    if(mst==-1) {//没有最小生成树即输出-1
        printf("-1\n");
        return;
    }
    for(int i=1;i<=nPos;i++){//对最小生成树的每条边进行遍历,选择删边后的最小值
        int secmst=secondTree(num[i]);
        if(secmst!=-1)//若没有次小生成树输出-1
            Min=min(Min,secmst);
        }
    if(Min!=inf&&Min!=mst)
        printf("%d\n",Min);
    else
        printf("-1\n");
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        read();
        solve();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44410512/article/details/86837787
今日推荐