jianupc

 

poj 1679 The Unique MST (次小生成树算法)

The Unique MST

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 16309   Accepted: 5652

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!

Source

 
 
 
View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
const int INF = 0x7ffffff;
const int MAXN = 105;
const int MAXM = 10005;
int n,m;                   //n是点的数目,m是边得数目
int mst,secmst;            //mst是最小生成树的大小,secmst是次小生成树的大小
struct node{
  int v,u,w;
  int select;              //标记是否在在最小生成树中
}edge[MAXM];
struct node1{              //一个等价类的邻接表
  int to;
  int next;
}links[MAXN];
int head[MAXN];            //头节点位置
int end[MAXN];             //尾节点位置,便于两条邻接表的合并
int length[MAXN][MAXN];    //每两点在最小生成树上路径中最长边长
int p[MAXN];               //并查集部分
int find(int x){
  if(x == p[x]) return x;
  p[x] = find(p[x]);
  return p[x];
}

bool cmp(node a, node b){
  if (a.w != b.w)return a.w<b.w;
  if (a.u != b.u)return a.u<b.u;
  return a.v<b.v;
}

void kruskal(){
  memset(head, -1, sizeof(head));
  int i,j,k,u;
  int x,y;
  for (i=1; i<=n; i++){          //初始化邻接表,对于每个节点添加一条指向其自身的边,表示以i为
    p[i] = i;                    //代表的集合只有点i;
    links[i].to = i;
    links[i].next = head[i];
    head[i] = i;
    end[i] = i;
  }
  sort(edge, edge+m, cmp);
  k = 0;
  for (i=0; i<m; i++){
    if (k == n-1) break;
    x = find(edge[i].u);
    y = find(edge[i].v);
    if (x != y){                 //遍历两个节点所在的集合
      for (j=head[x]; j!=-1; j=links[j].next)
        for (u=head[y]; u!=-1; u=links[u].next)
          length[links[j].to][links[u].to] = length[links[u].to][links[j].to] = edge[i].w;
      //每次合并两个等价类的时候,分别属于两个等价类的两点间的最长边一定是当前加入的边
      links[end[y]].next = head[x]; //合并两个邻接表
      end[y] = end[x];
      p[x] = y;
      k++;
      edge[i].select = 1;
      mst += edge[i].w;
    }
  }
}

int main(){
//  freopen("in.txt", "r", stdin);
  int i;
  int T;
  int u,v,w;
  scanf("%d",&T);
  while (T--){
    mst = 0;
    scanf("%d%d",&n,&m);
    for (i=0; i<m; i++){
      scanf("%d %d %d",&u,&v,&w);
        edge[i].u = u;
        edge[i].v = v;
        edge[i].w = w;
        edge[i].select = 0;
    }
    kruskal();
    secmst = INF;
    for (i=0; i<m; i++){
      if (!edge[i].select)
        secmst = min(secmst, mst+edge[i].w-length[edge[i].u][edge[i].v]);
    }
    if (secmst != mst)
      printf("%d\n",mst);
    else
      printf("Not Unique!\n");
  }
  return 0;
}

 

posted on 2013-03-22 17:50  shijianupc  阅读(189)  评论(0)    收藏  举报

导航