POJ 1679 判断MST的存在唯一性

 

The Unique MST

Description

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!

 

/*
   判定MST是否唯一的正确方法:
      1、对图中的每条边,扫描其他边,如果存在相同权值的边,则对该边进行标记。
      2、然后用Kruskal算法(或prim算法)求MST
      3、求得MST后,如果该MST中未包含做了标记的边,即可判定MST唯一;
         如果包含作了标记的边,则依次去掉这些边再求MST,如果求得的MST权值和
         原MST权值相同,即可判定MST不唯一。
*/

 

//我是用Kruskal算法求MST的

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;

const int maxn=10000;

struct node
{
   int u,v,w; //用于记录边的起始点以及边上的权值大小
   int eq,used,del; //eq用于标记是否存在权值相同的边,
   //used用于标记在第一次求得的MST中是否包含该边,del用于标记便是否被删除
  
   bool operator <(node a) const
   {
      return a.w>w;
   }
  
}edge[maxn];

int father[maxn];
int n,m;
bool first;

int find_father(int x)
{
   int r;
   for(r=x;father[r]>=0;r=father[r]);
   while(x!=r)
   {
      int temp=father[x];
      father[x]=r;
      x=temp;
   }
   return r;
}

void unit(int a,int b)
{
   int r1=find_father(a),r2=find_father(b);
   int temp=father[r1]+father[r2];
  
   if(father[r1]>father[r2])
   {father[r1]=r2;father[r2]=temp;}
   else
   {father[r2]=r1;father[r1]=temp;}
}

int kruskal()
{
   int num=0;
   int sum=0;
   int u,v;
  
   for(int i=0;i<=n;i++)
      father[i]=-1;
  
   for(int i=0;i<m;i++)
   {
      if(edge[i].del==1) continue;//如果边已被删除,则继续下一个
      u=edge[i].u,v=edge[i].v;
      if(find_father(u)!=find_father(v))
      {
         num++;
         sum+=edge[i].w;
         unit(u,v);
         if(first) edge[i].used=1;//如果只是第一次求MST,则将用到的边标记为1
      }
      if(num>=n-1) break;
   }
   return sum;
}

int main()
{
   int t,a,b,c;
   scanf("%d",&t);
   while(t--)
   {
      scanf("%d%d",&n,&m);
      for(int i=0;i<m;i++)
      {
         scanf("%d%d%d",&a,&b,&c);
         edge[i].u=a,edge[i].v=b,edge[i].w=c;
         edge[i].eq=0;edge[i].used=0;edge[i].del=0;
      }
      for(int i=0;i<m;i++)
         for(int j=0;j<m;j++)
         {
            if(i==j) continue;
            if(edge[i].w==edge[j].w) edge[j].eq=1; //存在相同的边,标记
         }
      sort(edge,edge+m);
      first=true;  //第一次求MST
      int w1=kruskal(),w2;
      first=false;
      int i;
      for(i=0;i<m;i++)
      {
         if(edge[i].used&&edge[i].eq)
         {
            edge[i].del=1; //用过的存在相同的边的边被删除
            w2=kruskal();
            if(w1==w2)
            {
               cout<<"Not Unique!\n";
               break;
            }
            edge[i].del=0;
         }
      }
      if(i>=m) printf("%d\n",w1);
   }
  
   return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值