【K - The Unique MST】

80 篇文章 0 订阅
80 篇文章 0 订阅

思路:

  • 最小生成树的唯一性,做法有两种。
    1. 多次 Kruskal。第一次 Kruskal 将最小生成树用到的所有边高亮并记录 ans,然后逐一删去某条边再 Kruaskal,若某次结果与 ans相同,则可证明树 not unique。注意可能删去某条边后原图不连通,要加入判断,否则会 WA优化:因为边数是固定的,所以仅将权值重复且用到的边高亮即可,如果边权唯一则不需删除之(只需要多加一个 same[])。
    2. 次小生成树

代码:

  • Kruskal:63ms 744kB
//63ms		744kB


#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 110;

int N,M;
int ans;
int par[maxn];
bool book[maxn * maxn / 2];
struct EDGE{
	int l,r,w;
	friend bool operator < (EDGE a , EDGE b)
	{
		return a.w < b.w;
	}
}edge[maxn * maxn / 2]; 
void ADDEDGE(int i,int l,int r,int w){
	edge[i].l = l;
	edge[i].r = r;
	edge[i].w = w;
	return ;
}

void INIT(){
	memset(book , 0 , sizeof(book));
	return ;
} 

int FIND(int i){
	return par[i] == -1 ? i : par[i] = FIND(par[i]);
}

void UNION(int l,int r){
	int parl = FIND(l);
	int parr = FIND(r);
	par[parr] = parl;
	return ;
}

int KRUSKAL(int jump){
	memset(par , -1 , sizeof(par));
	int tp = 0;
	for(int i=0;i<M;i++){ 
		if(i == jump)
			continue;
		int l = edge[i].l;
		int r = edge[i].r;
		int parl = FIND(l);
		int parr = FIND(r);
		if(parl != parr){
			UNION(l,r);
			tp += edge[i].w;
			if(jump == -1)
				book[i] = true;//最小生成树使用的边 
		}
	}
	for(int i=1;i<N;i++){
		if(FIND(i) != FIND(i+1))
		//注意范围
		{
			tp = -1;
			break;
		}
	}
	return tp;
}

int main(){
	int T;cin>>T;
	while(T--){
		INIT();
		cin>>N>>M;
		for(int i=0;i<M;i++){
			int l,r,w;
			cin>>l>>r>>w;
			ADDEDGE(i,l,r,w);
		}
		sort(edge , edge+M);
		ans = KRUSKAL(-1);//to get ans & book 
		for(int i=0;i<M;i++){
			if(book[i]){
				int tp;
				tp = KRUSKAL(i);
				if(tp == ans){
					ans = -1;
					break;
				}
			}
		}
		if(ans == -1)
			cout<<"Not Unique!"<<endl;
		else
			cout<<ans<<endl;
	}
	return 0;
}
  • Kruskal优化:79ms 752kB
//79ms		752kB


#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 110;

int N,M;
int ans;
int par[maxn];
bool book[maxn * maxn / 2];
bool same[maxn * maxn / 2];
struct EDGE{
	int l,r,w;
	friend bool operator < (EDGE a , EDGE b)
	{
		return a.w < b.w;
	}
}edge[maxn * maxn / 2]; 
void ADDEDGE(int i,int l,int r,int w){
	edge[i].l = l;
	edge[i].r = r;
	edge[i].w = w;
	return ;
}

void INIT(){
	memset(book , 0 , sizeof(book));
	memset(same , 0 , sizeof(same));
	return ;
} 

int FIND(int i){
	return par[i] == -1 ? i : par[i] = FIND(par[i]);
}

void UNION(int l,int r){
	int parl = FIND(l);
	int parr = FIND(r);
	par[parr] = parl;
	return ;
}

int KRUSKAL(int jump){
	memset(par , -1 , sizeof(par));
	int tp = 0;
	for(int i=0;i<M;i++){ 
		if(i == jump)
			continue;
		int l = edge[i].l;
		int r = edge[i].r;
		int parl = FIND(l);
		int parr = FIND(r);
		if(parl != parr){
			UNION(l,r);
			tp += edge[i].w;
			if(jump == -1)
				book[i] = true;//最小生成树使用的边 
		}
	}
	for(int i=1;i<N;i++){
		if(FIND(i) != FIND(i+1))
		{
			tp = -1;
			break;
		}
	}
	return tp;
}

int main(){
	int T;cin>>T;
	while(T--){
		INIT();
		cin>>N>>M;
		for(int i=0;i<M;i++){
			int l,r,w;
			cin>>l>>r>>w;
			ADDEDGE(i,l,r,w);
		}
		sort(edge , edge+M);
		for(int i=1;i<M;i++)
			if(edge[i-1].w == edge[i].w)
				same[i-1] = same[i] = true;
		ans = KRUSKAL(-1);//to get ans & book 
		for(int i=0;i<M;i++){
			if(book[i] && same[i]){
				int tp;
				tp = KRUSKAL(i);
				if(tp == ans){
					ans = -1;
					break;
				}
			}
		}
		if(ans == -1)
			cout<<"Not Unique!"<<endl;
		else
			cout<<ans<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值