POJ 1679 The Unique MST(判断最小生成树是否唯一)

7 篇文章 0 订阅
7 篇文章 0 订阅

题目链接:POJ 1679 The Unique MST

POJ 1679 The Unique MST(判断最小生成树是否唯一)

思路:枚举删边,再求最小生成树,相等则不唯一

判断最下生成树是否唯一的思路一:

1、对图中的每一条边,扫描其他边,如果存在相同权值的边,则对该边做标记。

2、然后用Kruskal算法或Prim算法求MST。

3、求得MST后,如果该MST中未包含做了标记的边,即可判断MST唯一;如果包含做了标记的边,则依次去掉这些边再求MST,如果求得的MST权值和原来的MST的权值一样,即可判断MST不唯一。

判断最下生成树是否唯一的思路二:(较为复杂)

首先求出原图最小生成树,权值之和为min 枚举添加每条不在最小生成树上的边 ,加上以后一定会形成一个环。
找到环上除了(u,v)以外的权值最大的边,把它删掉,计算当前生成树的权值之和。 枚举完所有边之后,得到的最小值即为次小生成树的权值。
具体实现时,更简单的方法是从每个节点i遍历整个最小生成树
定义F[i][j]为在生成树上,从i到j的路径上最大的边的权值。通过BFS,求出F[i][j]的值
然后对于添加每条不在最小生成树中的边(i,j),并删去该环中的原生成树的的最大边。 新的生成树权值之和就是Min + w(i,j) –
F[i][j] 记录其最小值,则为次小生成树。

次小生成树详解点这里

鄙人愚钝,用的删边枚举:
当且仅当第i条边与第j条边的权值相等,且MST中包含第i条边时,删去第i条边,再求MST.可以减掉多次枚举

/*************************************************************************
    > File Name: poj_1679.cpp
    > Author: dulun
    > Mail: dulun@xiyoulinux.org
    > Created Time: 2016年04月03日 星期日 17时38分34秒
 ************************************************************************/

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define LL long long
using namespace std; 
const int N = 50086;

bool first = 0;
int n, m;
int p[N];
struct Edge
{
    int s, e, w;
    bool same, use, del;
};
Edge e[N];

bool cmp(Edge a, Edge b) { return a.w < b.w; }
int find(int x) { return x == p[x] ? x : p[x] = find(p[x]); }

void init()
{
    for(int i = 0; i < N; i++) p[i] = i;
}

int kruscal()
{
    int cnt = 0, ans = 0;
    init();
    for(int i = 0; i < m; i++)
    {
        if(e[i].del == true) continue;
        int x = find(e[i].s);
        int y = find(e[i].e);
        if( x!=y )
        {
            p[x] = y;
            ans+=e[i].w;
            if(first) e[i].use = true;
            cnt++;   
        }
        if(cnt == n-1) return ans;
    }
    return ans;
}


void findSameWeight()
{
    for(int i = 0; i < m; i++)
    for(int j = 0; j < m; j++)
    {
        if(i==j) continue;
        if(e[i].w == e[j].w) e[i].same = true;
    }
}

void sovle()
{
    sort(e, e+m, cmp);
    first = true;
    int ans_MST = kruscal();
    first = false;
    for(int i = 0; i < m; i++)
    {
        if(e[i].use && e[i].same)
        {
            e[i].del = true;
            int ans = kruscal();
            e[i].del = false;
            if(ans == ans_MST) 
            {
                printf("Not Unique!\n");
                return ;
            }
        }   
    }
    printf("%d\n", ans_MST);
    return;
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        scanf("%d%d", &n, &m);
        for(int i = 0; i < m; i++)
        {
            int a, b, w;
            scanf("%d%d%d", &a, &b, &w);
            e[i].s = a, e[i].e = b, e[i].w = w;
            e[i].same = false;
            e[i].use = false;
            e[i].del = false;
        }
        findSameWeight();
        sovle();
    }
    return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值