poj1679 判断MST是否是唯一的

题目链接:http://poj.org/problem?id=1679

题目大意:就是给你一个图,然后让你判断该图的MST是否是唯一的

大概思路:就是用Kruskal或者prim第一次求出MST,并且标记第一次MST中有权值一样的边。如果发现该图没有相同的权值的边,那该图的MST是唯一的。否则依次删除MST中有被标记的权值相同的边并进行另一次MST,如果这次求的的MST的总权值和第一次是一样的那表示该图的MST是不唯一的,如果依次删除相同的权值的边后的MST的权值均与第一次的MST的权值不同那表示该图的MST是唯一的。

参考代码:

#include<iostream>
using namespace std;
#include<algorithm>
#define MAXN 105
int parent[MAXN],n,m;
struct node
{
	int u,v,w;
	int equal;//改变是否唯一 是为0 否为1
	int use;//改变是否使用,是为1 否为0
	int del;//改变是否被删除 是为1 否为0
}map[10000];
bool first;//记录是第一次就是MST中的边
void UFset()
{
	for(int i=0;i<n;i++)
		parent[i]=-1;
}
int Find(int x)
{
	int s,tmp;
	for(s=x;parent[s]>=0;s=parent[s]);
	while(s!=x)
	{
		tmp=parent[x];
		parent[x]=s;
		x=tmp;
	}
	return s;
}
void Union(int R1,int R2)
{
	int r1=Find(R1),r2=Find(R2);
	int tmp=parent[r1]+parent[r2];
	if(parent[r1]>parent[r2])
	{
		parent[r1]=r2;
		parent[r2]=tmp;
	}
	else
	{
		parent[r2]=r1;
		parent[r1]=tmp;
	}
}
bool cmp(node a,node b)
{
	return a.w<b.w;
}
int Kruskal()
{
	int sum=0;
	int num=0;
	int u,v,i;
	UFset();
	for(i=0;i<m;i++)
	{
		if(map[i].del==1)//如果该边是被删除的了,那就不处理
			continue;
		u=map[i].u,v=map[i].v;
		if(Find(u)!=Find(v))
		{
			sum+=map[i].w;
		    if(first)	
				map[i].use=1;//记录该边已经在MST中了
			Union(u,v);
			num++;
		}
		if(num>n)
			break;
	}
	return sum;
}
int main()
{
	int T,i,a,b,c;
	cin>>T;
	while(T--)
	{
		cin>>n>>m;
		for(i=0;i<m;i++)
		{
			cin>>a>>b>>c;
			map[i].u=a-1;map[i].v=b-1;map[i].w=c;
			map[i].equal=map[i].use=map[i].del=0;//初始化
		}
		for(i=0;i<m;i++)//标记权值相同的边
		{
			for(int k=0;k<m;k++)
			{
				if(i==k)
					continue;
				if(map[i].w==map[k].w)
					map[i].equal=1;
			}
		}
		sort(map,map+m,cmp);
		first=true;
		int weight1=Kruskal(),weight2;//第一次求MST
		first=false;
		int j;
		for( j=0;j<m;j++)//依次删除相同的权值的边并进行MST的求解
		{
			if(map[j].use&&map[j].equal)
			{
				map[j].del=1;
				weight2=Kruskal();
				if(weight1==weight2)
				{
					cout<<"Not Unique!"<<endl;
					break;
				}
				map[j].del=0;
			}
			
		}
		if(j>=m)
			cout<<weight1<<endl;
	}
	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值