Poj 1679 The Unique MST

题目描述:
给定一个连通无向网,判定它的最小生成树是否唯一。
输入描述:
输入文件的第1 行为一个整数t,1≤t≤20,表示测试数据的数目。每个测试数据描述了一个
连通无向网。每个测试数据的第1 行为两个整数:n 和m,1≤n≤100,分别表示顶点的数目和
边的数目。接下来有m 行,每行为一个三元组(xi, yi, wi),表示一条边(xi, yi),xi 和yi 表示边的两
个顶点,顶点序号从1 开始计起,这条边的权值为wi。任何两个顶点间最多只有一条边。
输出描述:
对输入文件中的每个测试数据,如果最小生成树是唯一的,则输出最小生成树的权;如果最

小生成树不唯一,则输出"Not Unique!"。


模版判断是否是唯一的最小生成树。这里借鉴一下:

判定最小生成树是否唯一的一个正确思路为:
1) 对图中每条边,扫描其他边,如果存在相同权值的边,则对该边作标记;
2) 然后用Kruskal 算法(或Prim 算法)求MST;
3) 求得MST 后,如果该MST 中未包含作了标记的边,即可判定MST 唯一;如果包含作了
标记的边,则依次去掉这些边再求MST,如果求得的MST 权值和原MST 的权值相同,即可判定
MST 不唯一。

so~~~~

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#define MAX 10500
#define INF 0x7FFFFFFF
# define eps 1e-5
using namespace std;
struct Edge//边的信息:起点 终点 权值 是否访问 是否删去 是否存在权值相等
{
    int s,e,value;
    int vis,del,equal;
} edge[MAX];
int n,m,par[105];
int mst;//第一次mst的标志
int find(int x)//查
{
    while(par[x] != x)
        x = par[x];
    return x;
}
void connect(int a,int b)//并
{
    if(a < b)
        par[b] = a;
    else
        par[a] = b;
}
bool cmp(Edge a, Edge b)//比
{
    return a.value < b.value;
}
int kruskal()
{
    int i,j,sum = 0;
    for(i=1; i<=n; i++)
        par[i] = i;
    for(i=1; i<=m; i++)
    {
        int a = find(edge[i].s);
        int b = find(edge[i].e);
        if(!edge[i].del && a != b)
        {
            connect(a,b);
            sum += edge[i].value;
            if(mst == 1)
            {
                edge[i].vis = 1;
            }
        }
    }
    return sum ;
}
int main()
{
    int t,i,j;
    scanf("%d",&t);
    while(t --)
    {
        scanf("%d%d",&n,&m);
        for(i=1; i<=m; i++)//初始化以及构图
        {
            scanf("%d%d%d",&edge[i].s,&edge[i].e,&edge[i].value);
            edge[i].del = 0;
            edge[i].vis = 0;
            edge[i].equal = 0;
        }
        for(i=1; i<=m; i++)//找出有相等权值的边
            for(j=1; j<=m; j++)
            {
                if(i != j && edge[i].value == edge[j].value)
                {
                    edge[i].equal = 1;
                }
            }
        sort(edge+1,edge+1+m,cmp);
        mst = 1;
        int sum1 = kruskal();
        int ok = 1;//作为是否mst不唯一的标志
        mst = 0;
        for(i=1; i<=m; i++)
        {
            if(edge[i].vis && edge[i].equal )
            {
                edge[i].del = 1;//依次去掉权值相等的边,再求mst
                int sum2 = kruskal();
                if(sum2 == sum1)//两次权值相等
                {
                    printf("Not Unique!\n");
                    ok = 0;
                    break;
                }
                edge[i].del = 0;//删去的边补回来
            }
        }
        if(ok == 1)
        {
            printf("%d\n",sum1);
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值