(kuangbin带你飞--最小生成树)The Unique MST(次小生成树)

原文章:

Given a connected undirected graph, tell if its minimum spanning tree is unique.

Definition 1 (Spanning Tree): Consider a connected, undirected graph G = (V, E). A spanning tree of G is a subgraph of G, say T = (V', E'), with the following properties:
1. V' = V.
2. T is connected and acyclic.

Definition 2 (Minimum Spanning Tree): Consider an edge-weighted, connected, undirected graph G = (V, E). The minimum spanning tree T = (V, E') of G is the spanning tree that has the smallest total cost. The total cost of T means the sum of the weights on all the edges in E'.

Input

The first line contains a single integer t (1 <= t <= 20), the number of test cases. Each case represents a graph. It begins with a line containing two integers n and m (1 <= n <= 100), the number of nodes and edges. Each of the following m lines contains a triple (xi, yi, wi), indicating that xi and yi are connected by an edge with weight = wi. For any two nodes, there is at most one edge connecting them.

Output

For each input, if the MST is unique, print the total cost of it, or otherwise print the string 'Not Unique!'.

Sample Input

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

Sample Output

3
Not Unique!

中文概要:

从前有两只猫。它们实在不知道该出什么题了。
于是它们放弃了治疗,开始玩一个游戏:从乡镇地图中已有的道路里面删除一些道路,并且删除完毕后图仍然是连通的。在所有方案中,删除道路总长度最大的方案为最优方案。
两只猫同时完成了这个游戏。它们都坚信自己是赢家。已知它们的完成方式不同,请判断有没有可能它们的实现方案都是最优的。
Input
第一行是一个整数 t (1 <= t <= 20), 测试用例的数量。每个用例代表一张图,第一行是n和m (1 <= n <= 100), 分别为城镇数和道路数。接下来m行为m个三元组 (xi, yi, wi),表示编号为xi和yi的城镇被长度为wi的道路连接。两个城镇之间最多被一条道路连接。
Output
对于每个用例,如果答案为否定(即不可能都是最优方案),输出最优方案剩余的(注意不是删除的)道路总长度。否则输出字符串 ‘Not Unique!’(不带引号)。
 

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
using namespace std;
const int manx=200+5;
const int mamx=1e5+5;
int n,m,u,v,w,k;
int f[manx],d[manx][manx];  //d数组用来维护u到v的距离,在枚举边的时候会用到
vector<int>p[manx]; //扩展路径,path数组,缩写p
struct node{
    int u,v,w;
    bool vis;  //比常规最小生成树多了vis属性判断边是否加入最小生成树的集合
}a[mamx];
bool cmp(node a,node b)
{
    return a.w<b.w;
}
int find(int x)
{
    if(f[x]==x) return x;
    else return f[x]=find(f[x]);
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        k=0;
        scanf("%d%d",&n,&m); 
        for(int i=1;i<=n;i++){   //初始化操作,万物之父皆自己
            p[i].clear();  
            p[i].push_back(i);
            f[i]=i;
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            a[++k].u=u,a[k].v=v,a[k].w=w,a[i].vis=false;
        }
        sort(a+1,a+1+k,cmp);
        ll ans=0;
        int total=1;
        for(int i=1;i<=k;i++)
        {
            u=find(a[i].u),v=find(a[i].v);
            if(u==v) continue;
            ans+=a[i].w;
            f[u]=v; 
            a[i].vis=1; //标记进去最小生成树的集合
            total++;
            int l1=p[u].size(),l2=p[v].size(); 
            for(int j=0;j<l1;j++)
                for(int k=0;k<l2;k++)
                    d[p[u][j]][p[v][k]]=d[p[v][k]][p[u][j]]=a[i].w; //记录最小生成树中扩展路径的距离
            for(int j=0;j<l1;j++) p[v].push_back(p[u][j]); //合并路径 
            if(total==n) break;
        }
        ll res=inf; //次小生成树的集合
        for(int i=1;i<=k;i++)
            if(!a[i].vis)  //枚举每条没加入最小生成树的集合
                res=min(res,ans+a[i].w-d[a[i].u][a[i].v]); 
        //ans是最小生成树的权值,减去最小生成树中u到v这条边的权值,加上枚举的这一条边进行比较
        if(res>ans) cout<<ans<<endl;
        else cout<<"Not Unique!"<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

deebcjrb

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

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

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

打赏作者

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

抵扣说明:

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

余额充值