题目链接:http://poj.org/problem?id=1679
题意是给了n个点,m条边,问最小生成树是否唯一
首先我们求一个最小生成树把每条边记录下来,然后我们对这个最小生成树进行删边操作,再删除一条边后,能不能再生成一个权值相同的最小生成树就行了。我刚开始有一个错误的想法,但是感觉是对的...就是我们求一个最小生成树,然后把每条边和他的权值记录下来,然后再去遍历所有边去找没有记录过的边而且权值已经出现过的边,这样的话就不是唯一的最小生成树了。然而这画个图就可以看出来显然是错的,因为会出现不连通的情况。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
#define maxn 105
using namespace std;
struct Node{
int x,y,w;
bool operator < (const Node &a) const{
return a.w > w;
}
}Edge[maxn * maxn];
int pre[maxn],cnt[maxn],num;
int T,n,m,ans;
bool flag;
void init(){
for(int i=0;i<=n;i++) pre[i] = i;
}
void add(int u,int v,int w){
Edge[num].x = u;
Edge[num].y = v;
Edge[num++].w = w;
}
int Find(int x){
if(x != pre[x]) pre[x] = Find(pre[x]);
return pre[x];
}
void Kruskal(){
ans = 0;
int xx = 0;
sort(Edge, Edge + num);
for(int i=0;i<m;i++){
int fx = Find(Edge[i].x);
int fy = Find(Edge[i].y);
if(fx != fy){
pre[fy] = fx;
cnt[xx++] = i;
ans += Edge[i].w;
}
}
for(int k=0;k<xx;k++){
init();
int sum = 0;
int yy = 0;
for(int i=0;i<m;i++){
if(i == cnt[k]) continue;
int fx = Find(Edge[i].x);
int fy = Find(Edge[i].y);
if(fx != fy){
pre[fy] = fx;
yy ++;
sum += Edge[i].w;
}
}
if(yy == n - 1 && sum == ans){
flag = false;
return ;
}
}
}
int main()
{
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
init();
for(int i=0;i<m;i++){
int u, v, w;
scanf("%d%d%d",&u,&v,&w);
add(u, v, w);
// add(v, u, w);
}
num = 0;
flag = true;
Kruskal();
if(flag) printf("%d\n", ans);
else puts("Not Unique!");
}
return 0;
}