[POJ 1679] The Unique MST 最小树

http://poj.org/problem?id=1679

题意:给你一棵树,判断最小树是不是唯一的。

思路:求最小树,保存最小树中的边,然后枚举所有不再树中的边,将这条边加入树中,判断形成的环中是否有两条一样的边,如果有那么最小树就不唯一。

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>

using namespace std;


int n, m;
int mapn[105][105];

int dis[105];  //最小树中每个点到前驱的距离
int pre[105]; //保存最小数种每个点的前驱
bool vis[105]; //标记数组
int maxn[105][105];  //最小树中 i - k 这条路中的最长的边
bool intr[105][105]; //i - k 是否在最小树中

int Prim(int rt)
{
    memset(vis, false, sizeof(vis));
    memset(intr, false, sizeof(intr));
    int res = 0;
    vis[rt] = true;
    for(int i = 1; i <= n; i++){
        pre[i] = rt;
        dis[i] = mapn[rt][i];
    }
    for(int k = 1; k < n; k++){
        int mid = -1;
        for(int i = 1; i <= n; i++){
            if(!vis[i] && (mid == -1 || dis[mid] > dis[i])){
                mid = i;
            }
        }
        res += dis[mid];
        vis[mid] = true;
        intr[mid][pre[mid]] = intr[pre[mid]][mid] = true;
        for(int i = 1; i <= n; i++){
            if(vis[i]){  //更新 i - mid 路径中的最大距离
                int x = maxn[i][pre[mid]];
                int y = mapn[mid][pre[mid]];
                maxn[i][mid] = maxn[mid][i] = x > y ? x : y;
            }
            else if(dis[i] > mapn[mid][i]){
                pre[i] = mid;
                dis[i] = mapn[mid][i];
            }
        }
    }
    return res;
}

int main()
{
    int Test;
    scanf("%d", &Test);
    while(Test--){
        int x, y, val;
        scanf("%d%d", &n, &m);
        memset(mapn, 127, sizeof(mapn));
        for(int i = 0; i < m; i++){
            scanf("%d%d%d", &x, &y, &val);
            mapn[x][y] = val;
            mapn[y][x] = val;
        }
        int sum = Prim(1);
        bool flag = false;
        for(int i = 1; i <= n; i++){
            for(int k = i+1; k <= n; k++){
                if(!intr[i][k] && maxn[i][k] == mapn[i][k]){
                    flag =  true;
                    break;
                }
            }
        }
        if(flag){
            printf("Not Unique!\n");
        }
        else{
            printf("%d\n", sum);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

achonor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值