http://poj.org/problem?id=1679
题意:给你一棵树,判断最小树是不是唯一的。
思路:求最小树,保存最小树中的边,然后枚举所有不再树中的边,将这条边加入树中,判断形成的环中是否有两条一样的边,如果有那么最小树就不唯一。
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
int n, m;
int mapn[105][105];
int dis[105]; //最小树中每个点到前驱的距离
int pre[105]; //保存最小数种每个点的前驱
bool vis[105]; //标记数组
int maxn[105][105]; //最小树中 i - k 这条路中的最长的边
bool intr[105][105]; //i - k 是否在最小树中
int Prim(int rt)
{
memset(vis, false, sizeof(vis));
memset(intr, false, sizeof(intr));
int res = 0;
vis[rt] = true;
for(int i = 1; i <= n; i++){
pre[i] = rt;
dis[i] = mapn[rt][i];
}
for(int k = 1; k < n; k++){
int mid = -1;
for(int i = 1; i <= n; i++){
if(!vis[i] && (mid == -1 || dis[mid] > dis[i])){
mid = i;
}
}
res += dis[mid];
vis[mid] = true;
intr[mid][pre[mid]] = intr[pre[mid]][mid] = true;
for(int i = 1; i <= n; i++){
if(vis[i]){ //更新 i - mid 路径中的最大距离
int x = maxn[i][pre[mid]];
int y = mapn[mid][pre[mid]];
maxn[i][mid] = maxn[mid][i] = x > y ? x : y;
}
else if(dis[i] > mapn[mid][i]){
pre[i] = mid;
dis[i] = mapn[mid][i];
}
}
}
return res;
}
int main()
{
int Test;
scanf("%d", &Test);
while(Test--){
int x, y, val;
scanf("%d%d", &n, &m);
memset(mapn, 127, sizeof(mapn));
for(int i = 0; i < m; i++){
scanf("%d%d%d", &x, &y, &val);
mapn[x][y] = val;
mapn[y][x] = val;
}
int sum = Prim(1);
bool flag = false;
for(int i = 1; i <= n; i++){
for(int k = i+1; k <= n; k++){
if(!intr[i][k] && maxn[i][k] == mapn[i][k]){
flag = true;
break;
}
}
}
if(flag){
printf("Not Unique!\n");
}
else{
printf("%d\n", sum);
}
}
return 0;
}