http://poj.org/problem?id=1679
题目大意:
给你一些点,判断MST(最小生成树)是否唯一。
--------------------------------------------------------此题已更新最新题解报告--------------------------------------------------------
http://blog.csdn.net/murmured/article/details/18868481
思路:
首先先建立MST,然后把这个MST的边一个个尝试不使用,构建另外一颗MST,然后判断权值是否相等。
这样复杂度需要O(n^3)。。
还可以用次最小生成树的方法解决。
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=101;
int fa[MAXN];
struct point
{
int x,y;
int len;
}data[MAXN*MAXN],pre[MAXN*MAXN]; //pre 记录等一下用到了哪些条边
bool operator < (const point &a ,const point &b) //sort 重载比较函数
{
return a.len<b.len;
}
void UFinit(int n) //并查集初始化
{
for(int i=1;i<=n;i++)
fa[i]=i;
}
int find(int cur) //带路径压缩的并查集查询函数,简洁而优雅~
{
return fa[cur]==cur? cur : fa[cur]=find(fa[cur]);
}
int kruskal(int n,int m,int &prelen)
{
UFinit(n);
int ans=0;
for(int i=0;i<m;i++)
{
int rootx=find(data[i].x);
int rooty=find(data[i].y);
if(rootx!=rooty)
{
fa[rootx]=rooty;
ans+=data[i].len;
pre[prelen++]=data[i];
}
}
return ans;
}
int kruskal2(int n,int m,int nox,int noy)//nox noy 代表直接连接这两个点之间的边不选
{
UFinit(n);
int ans=0;
for(int i=0;i<m;i++)
{
if(data[i].x==nox && data[i].y==noy)
continue;
int rootx=find(data[i].x);
int rooty=find(data[i].y);
if(rootx!=rooty)
{
fa[rootx]=rooty;
ans+=data[i].len;
}
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
scanf("%d%d%d",&data[i].x,&data[i].y,&data[i].len);
int prelen=0; //pre数组的长度
sort(data,data+m); //kruskal 前面的工作
int ans=kruskal(n,m,prelen); //正常版本的kruskal
bool unique=true;
for(int i=0;i<prelen;i++)
{
int res=kruskal2(n,m,pre[i].x,pre[i].y);//带去除边的kruskal
int cnt=0;
for(int j=1;j<=n;j++)
if(fa[i]==i)
cnt++;
if(cnt!=0) //这个很重要!没有就WA,因为可能剩下的不连通,但是恰好res==ans
continue;
if(res==ans) //如果还有一棵生成树和第一次所求的权值一样,说明最小生成树不唯一
{
unique=false;
break;
}
}
if(unique)
printf("%d\n",ans);
else
printf("Not Unique!\n");
}
return 0;
}