题目链接:POJ 1679 The Unique MST
思路:枚举删边,再求最小生成树,相等则不唯一
判断最下生成树是否唯一的思路一:
1、对图中的每一条边,扫描其他边,如果存在相同权值的边,则对该边做标记。
2、然后用Kruskal算法或Prim算法求MST。
3、求得MST后,如果该MST中未包含做了标记的边,即可判断MST唯一;如果包含做了标记的边,则依次去掉这些边再求MST,如果求得的MST权值和原来的MST的权值一样,即可判断MST不唯一。
判断最下生成树是否唯一的思路二:(较为复杂)
首先求出原图最小生成树,权值之和为min 枚举添加每条不在最小生成树上的边 ,加上以后一定会形成一个环。
找到环上除了(u,v)以外的权值最大的边,把它删掉,计算当前生成树的权值之和。 枚举完所有边之后,得到的最小值即为次小生成树的权值。
具体实现时,更简单的方法是从每个节点i遍历整个最小生成树
定义F[i][j]为在生成树上,从i到j的路径上最大的边的权值。通过BFS,求出F[i][j]的值
然后对于添加每条不在最小生成树中的边(i,j),并删去该环中的原生成树的的最大边。 新的生成树权值之和就是Min + w(i,j) –
F[i][j] 记录其最小值,则为次小生成树。
鄙人愚钝,用的删边枚举:
当且仅当第i条边与第j条边的权值相等,且MST中包含第i条边时,删去第i条边,再求MST.可以减掉多次枚举
/*************************************************************************
> File Name: poj_1679.cpp
> Author: dulun
> Mail: dulun@xiyoulinux.org
> Created Time: 2016年04月03日 星期日 17时38分34秒
************************************************************************/
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define LL long long
using namespace std;
const int N = 50086;
bool first = 0;
int n, m;
int p[N];
struct Edge
{
int s, e, w;
bool same, use, del;
};
Edge e[N];
bool cmp(Edge a, Edge b) { return a.w < b.w; }
int find(int x) { return x == p[x] ? x : p[x] = find(p[x]); }
void init()
{
for(int i = 0; i < N; i++) p[i] = i;
}
int kruscal()
{
int cnt = 0, ans = 0;
init();
for(int i = 0; i < m; i++)
{
if(e[i].del == true) continue;
int x = find(e[i].s);
int y = find(e[i].e);
if( x!=y )
{
p[x] = y;
ans+=e[i].w;
if(first) e[i].use = true;
cnt++;
}
if(cnt == n-1) return ans;
}
return ans;
}
void findSameWeight()
{
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].same = true;
}
}
void sovle()
{
sort(e, e+m, cmp);
first = true;
int ans_MST = kruscal();
first = false;
for(int i = 0; i < m; i++)
{
if(e[i].use && e[i].same)
{
e[i].del = true;
int ans = kruscal();
e[i].del = false;
if(ans == ans_MST)
{
printf("Not Unique!\n");
return ;
}
}
}
printf("%d\n", ans_MST);
return;
}
int main()
{
int t;
cin>>t;
while(t--)
{
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++)
{
int a, b, w;
scanf("%d%d%d", &a, &b, &w);
e[i].s = a, e[i].e = b, e[i].w = w;
e[i].same = false;
e[i].use = false;
e[i].del = false;
}
findSameWeight();
sovle();
}
return 0;
}