Codeforces Round #535 (Div. 3) F.MST Unification(最小生成树性质)

探讨通过调整边权值使最小生成树(MST)唯一的算法,介绍Kruskal算法应用,分析相同权值边对MST的影响,提供解决策略及C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

给你一张图,n个点m条边,

以下m条无向边ui,vi,wi

你可以令某条边权值加1,视为一次操作,

问,令最小生成树唯一时,最少操作数是多少

思路来源

https://www.cnblogs.com/shuaihui520/p/10320158.html

题解

考虑Kruskal加边过程,

一条边在合并的时候,u和v已然在一个集合,加入这条边会成环,不取

而剩下的边,加入就不会成环,说明可以被加入MST,统计一下权值相同的这些边的数量num

然后再遍历一下这些权值相同的边,

注意到之所以会出现最小生成树,是因为使现有树和一些点联通有多种方式,但其拓展的点集是一样的

所以,这些边中碰到一条可以加入MST的边就加入,那么和那个点就联通了,num--

剩下的权值相同的原属于num里的边,此刻再加入就成环了

最后num数就是,原本可以加入MST,但因一些和它相同权值的边的加入,最终未能加入MST的边

 

这道题的操作是对这些边的边权w+1,

会不会和原本就是w+1的边再冲突呢?

我们注意到,由于选了一些w的边,

使得这些被+1的边再被选的话一定会成环,

所以,不会影响w+1的MST边。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2e5+10;
struct edge{int u,v,w;}e[maxn];
bool operator<(edge a,edge b)
{
	return a.w<b.w;
}
int n,m,par[maxn],ans;
int find(int x)
{
	return par[x]==x?x:par[x]=find(par[x]);
}
int main()
{
	for(int i=1;i<maxn;++i)par[i]=i;
	scanf("%d%d",&n,&m);
	for(int i=0;i<m;++i)
	scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
	sort(e,e+m);
	for(int i=0;i<m;)
	{
	int j=i;
	while(j+1<m&&e[j+1].w==e[i].w)j++;
	int tmp=0;
	for(int k=i;k<=j;++k)
	if(find(e[k].u)!=find(e[k].v))tmp++;
	for(int k=i;k<=j;++k)
	{
		int uu=find(e[k].u),vv=find(e[k].v);
		if(uu!=vv)
		{
			if(uu>vv)par[uu]=vv;
			else par[vv]=uu;
			tmp--;
		}
	}
	ans+=tmp;
	i=j+1;
    }
    printf("%d\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值