poj-1679-The Unique MST-最小生成树是否唯一

本文介绍了一种基于Kruskal算法的简单变形来判断最小生成树(MST)是否唯一的算法。通过优化搜索相同边权重的过程,确保了时间复杂度在O(M+MlogM)内,并详细展示了算法实现的C++代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

判断MST(最小生成树)是否唯一的算法:

下面给大家介绍用Kruscal的简单变形就可以解决本题,时间复杂度为O(M+MlogM),包括了快排的时间复杂度,0MS。

注意到Kruscal贪心每次找出边权最小的边判断能否合并,假设找到了一条边权最小的边,其两个顶点所在集合的根节点分别为x和y,

向后搜寻边权与当前边相同的边(即当前边权最小的边不唯一),若搜寻到的边两个顶点的根节点同样是x和y,则这两个集合合并就有了两种方法,

此时就可以直接输出NotUnique!并退出。这样除了qsort以外的时间复杂度就被控制在O(m)以内。

#include <iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
using namespace std;
#define maxm 20000
#define maxn 150
struct list
{
    int u,v,w;
    friend bool operator < (const list &a,const list &b)
    {
        return a.w<b.w;
    }
} edge[maxm],p,q;
int vis[maxm];
int f[maxn];
int find(int x)
{
    while(x!=f[x])x=f[x];
    return x;
}
int vp[maxm];
int maps[maxn][maxn];
int pan(int a,int b,int c,int d)
{
    if(a==c&&b==d)return 1;
    if(a==d&&b==c)return 1;
    return 0;
}
int main()
{
    int T,n,m,i;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        memset(maps,0,sizeof(maps));
        for(i=1; i<=n; i++)f[i]=i;
        for(i=1; i<=m; i++)scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
        sort(edge+1,edge+m+1);
        memset(vis,0,sizeof(vis));
        for(i=2; i<=m; i++)
        {
            if(edge[i].w==edge[i-1].w)vis[i]=vis[i-1]=1;
        }
        int ans=0;
        int leap=0;
        int j;
        queue<list>que;
        while(!que.empty())que.pop();
        for(i=1; i<=m; i++)
        {
            int a=find(edge[i].u);
            int b=find(edge[i].v);
            if(a==b)continue;
            p.u=a;
            p.v=b;
            que.push(p);
            for(j=i+1;j<=m;j++)
            {
                if(edge[j].w==edge[i].w)
                {
                    int aa=find(edge[j].u);
                    int bb=find(edge[j].v);
                    if(aa==bb)continue;
                    p.u=a;
                    p.v=b;
                    que.push(p);
                }
                else break;
            }
            i=j-1;
            while(!que.empty())
            {
                p=que.front();
                que.pop();
                a=p.u;
                b=p.v;
                if(f[a]==b||f[b]==a)
                {
                    leap=1;
                    break;
                }
                f[a]=b;
            }
            if(leap==1)break;
            ans+=edge[i].w;
            f[a]=b;
        }
        if(leap)cout<<"Not Unique!"<<endl;
        else cout<<ans<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值