题目链接:
http://poj.org/problem?id=1679
解题思路:
1.首先求出原图的最小生成树,并将此生成树的每条边作标记;
2.每次只删除其中一条边,再求最小生成树,观察结果与最开始的是否一致,是则不唯一;
3.当所有被标记的边都被删过一次后,如果没有一次结果与最开始的一致,则是唯一的。
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,m;
struct Edge
{
int u,v,w;
int flag;
}edge[100005];
int pa[110];
int del[110];
bool cmp(Edge a,Edge b)
{
return a.w < b.w;
}
void init(){
for(int i = 1; i <= n; i++)
pa[i] = i;
}
int findset(int x)
{
if(pa[x] != x)
pa[x] = findset(pa[x]);
return pa[x];
}
int kruskal(int dell)
{
int i,u,v,cnt = n,sum = 0;
for(i = 0; i < m; i++)
{
if(i == dell)
continue;
u = findset(edge[i].u);
v = findset(edge[i].v);
if(u != v)
{
sum += edge[i].w;
pa[v] = u;
edge[i].flag = 1;
if(--cnt == 1)
break;
}
}
return sum;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
int u,v,w;
for(int 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].flag = 0;
}
sort(edge,edge+m,cmp);
int ans,ans1,tmp = 0,k = 0;
init();
ans = kruskal(-1);
for(int i = 1; i <= n; i++)
if(pa[i] == i)
tmp++;
if(tmp > 1){
printf("0\n");
continue;
}
for(int i = 0; i < m; i++)
if(edge[i].flag)
del[k++] = i;
int flag = 0;
for(int i = 0; i < k; i++){
init();
ans1 = kruskal(del[i]);
tmp = 0;
for(int j = 1; j <= n; j++)
if(pa[i] == i)
tmp++;
if(tmp > 1)
continue;
if(ans1 == ans){
flag = 1;
break;
}
}
if(flag)
printf("Not Unique!\n");
else
printf("%d\n",ans);
}
return 0;
}