7-24 最小生成树的唯一性 (35分)

7-24 最小生成树的唯一性 (35分)

给定一个带权无向图,如果是连通图,则至少存在一棵最小生成树,有时最小生成树并不唯一。本题就要求你计算最小生成树的总权重,并且判断其是否唯一。

输入格式:

首先第一行给出两个整数:无向图中顶点数 N(≤500)和边数 M。随后 M 行,每行给出一条边的两个端点和权重,格式为“顶点1 顶点2 权重”,其中顶点从 1 到N 编号,权重为正整数。题目保证最小生成树的总权重不会超过 2​30​​。

输出格式:

如果存在最小生成树,首先在第一行输出其总权重,第二行输出“Yes”,如果此树唯一,否则输出“No”。如果树不存在,则首先在第一行输出“No MST”,第二行输出图的连通集个数。

输入样例 1:

5 7
1 2 6
5 1 1
2 3 4
3 4 3
4 1 7
2 4 2
4 5 5

输出样例 1:

11
Yes

输入样例 2:

4 5
1 2 1
2 3 1
3 4 2
4 1 2
3 1 3

输出样例 2:

4
No

输入样例 3:

5 5
1 2 1
2 3 1
3 4 2
4 1 2
3 1 3

输出样例 3:

No MST
2

 这个题不单单是让求最小生成树的总路径长度,而且还让判断最小生成树的唯一性。因为对并查集印象比较深刻,我首先想到了克鲁斯卡尔算法,可在判断最小生成树的唯一性上老是出错,最后不得已,剽窃了他人的劳动成果,将自己写的代码按照别人的想法做了修改,结果就过了,不过心里还是很不爽。在思考过程中,我甚至想到了“去边法重新构造法”,这种方法十有八九会超时,就把这个方案否决了。用Prim算法可能更直接,不过我和Prim算法还不是很熟,也把这个方法舍弃了。这个题的Kruskal解法见如下代码:

#include <iostream>
#include <algorithm>
using namespace std;
struct Book{
    int u,v,w;
}book[125010];
int V[520],ans = 0;
int p[520],r[520];
int G[520][520]={0};
bool cmp(Book a,Book b){
    if(a.w!=b.w)
        return a.w<b.w;
    return false;
}
void Init(int n)
{
    for(int i=0;i<=n;i++)
    {
        r[i] = 0;
        p[i] = i;
    }
}
int Find(int x){
    return x==p[x]?x:p[x]=Find(p[x]);
}
void Union(int x,int y)
{
    x = Find(x);y=Find(y);
    if(x==y)return ;
    if(r[x]>r[y])
        p[y] = x;
    else if(r[y]>r[x])
        p[x] = y;
    else{
        p[x] = y;
        r[y]++;
    }
}
int main()
{
    //freopen("in","r",stdin);
    int n,m;scanf("%d%d",&n,&m);Init(n);
    for(int i=0;i<m;i++)
        scanf("%d%d%d",&book[i].u,&book[i].v,&book[i].w);
    sort(book,book+m,cmp);
    int cnt = 0,all = 0,flag = 0;
    for(int i=0;i<m;i++){
        int pu,pv;
        int u = book[i].u,v=book[i].v;
        u=Find(u),v=Find(v);
        if(u!=v){
            for(int j=i+1;j<m;j++){
                if(book[j].w==book[i].w){
                    pu=Find(book[j].u);pv=Find(book[j].v);
                    if((pu==u&&pv==v)||(pv==u&&pu==v))
                        flag=1;
                }else{
                    break;
                }
            }
            Union(u,v);
            cnt++;
            all+=book[i].w;
        }
    }
    if(cnt==n-1)
    {
        printf("%d\n",all);
        if(flag)
            printf("No\n");
        else
            printf("Yes\n");
    }else{
        printf("No MST\n");
        cnt = 0;
        for(int i=1;i<=n;i++)
            if(p[i]==i)cnt++;
        printf("%d\n",cnt);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zw201909250425/article/details/106101812