| Time Limit: 1000MS | Memory Limit: 10000K | |
| Total Submissions: 21646 | Accepted: 7661 |
Description
Input
Output
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
题目链接:http://poj.org/problem?id=1679
题目大意:判断最小生成树是否唯一
题目分析:对图中的每条边,扫瞄其他边,如果存在权值相同的边则标记,然后用Kruskal求最小生成树,如果该MST中未包含标记的边,则必唯一直接输出权值,否则依次去掉这些边再求MST,若两次求得的权值相同,则说明不唯一
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int const MAXN = 105;
int const MAXM = 6000;
int m, n;
int fa[MAXN], rank[MAXN];
bool fir, flag;
struct Edge
{
int u, v, w;
bool equal, used, del;
}e[MAXM];
bool cmp(Edge a, Edge b)
{
return a.w < b.w;
}
void UFset()
{
for(int i = 0; i <= n; i++)
fa[i] = i;
memset(rank, 0, sizeof(rank));
}
int Find(int x)
{
return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
void Union(int a, int b)
{
int r1 = Find(a);
int r2 = Find(b);
if(r1 == r2)
return;
if(rank[r1] > rank[r2])
fa[r2] = r1;
else
{
fa[r1] = r2;
if(rank[r1] == rank[r2])
rank[r1]++;
}
}
int Kruskal()
{
int u, v;
int num = 0, sum = 0;
UFset();
for(int i = 0; i < m; i++)
{
if(e[i].del)
continue;
u = e[i].u;
v = e[i].v;
if(Find(u) != Find(v))
{
sum += e[i].w;
Union(u, v);
num++;
if(fir)
e[i].used = true;
}
if(num == n - 1)
break;
}
return sum;
}
int main()
{
int T, u, v, w;
scanf("%d", &T);
while(T--)
{
flag = false;
scanf("%d %d", &n, &m);
for(int i = 0; i < m; i++)
{
scanf("%d %d %d", &e[i].u, &e[i].v, &e[i].w);
e[i].equal = e[i].used = e[i].del = false;
}
sort(e, e + m, cmp);
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].equal = true;
}
}
fir = true;
int w1 = Kruskal(), w2;
fir = false;
for(int i = 0; i < m; i++)
{
if(e[i].used && e[i].equal)
{
e[i].del = true; //删去这条边
w2 = Kruskal();
if(w1 == w2)
{
printf("Not Unique!\n");
flag = true;
break;
}
e[i].del = false;
}
}
if(!flag)
printf("%d\n", w1);
}
}
POJ 1679 The Unique MST (Kruskal 判最小生成树是否唯一)
原文地址:http://blog.csdn.net/tc_to_top/article/details/43671975