MST Unification

给定一个有n个点,m条边的无向连通图,每条边有边权。

定义一次操作为:选择一条图中的边,并将其权值+1。

试求最小的操作次数,使得操作后的图的最小生成树是唯一的。

1<=N<=2e5

n-1<=m<=2e5

 

Sol:

考虑在使用krustal进行加边操作

在加边的时候,我们会进行排序操作,对吧

于是在将所有边升序排列出来后,将具有相同权值的边找出来.

检查下这些边能连通多少个块,计为ans,例如下图

 其可连通3个不同的块

接下来我们进行实际操作,每次加边进行,如果发现两个点不在一个集合中

则当前边是可以直接使用的,于是ans--

最终发现有一条边是不能加进去的,于是这条边的权值就是要按题意进行累加的。

 

大家可自行处理下这个样例

 会发现使用边权为3的边

由于1与5已在一个集合中了,于是只连通2个集合,ans的值为1

在实际加边操作中,也就只能使用1--2这条边了。

最终这个样例的MST是唯一的。

 

 

 

#include<bits/stdc++.h>
using namespace std;
const int NN=2e5+4;
struct node
{
	int u,v,w;
	bool use;
	bool operator<(const node&it)const
	{
		return w<it.w;
	}
}edge[NN];
int fa[NN],maxx[NN];
int find(int x)
{
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		fa[i]=i;
	for(int i=1;i<=m;i++)
		scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
	sort(edge+1,edge+1+m);
	int ans=0,i=1;
	while(i<=m)
	{
		int j=i;
		while(edge[i].w==edge[j].w)
			j++;
		for(int k=i;k<j;k++)
			if(find(edge[k].u)!=find(edge[k].v))
				ans++;
		for(int k=i;k<j;k++)
		{
			int fu=find(edge[k].u),fv=find(edge[k].v);
			if(fu!=fv)
			{
				ans--;
				fa[fv]=fu;
			}
		}
		i=j;
	}
	printf("%d",ans);
	return 0;
}

 

  

 

 

posted @ 2023-06-19 21:53  我微笑不代表我快乐  阅读(27)  评论(0编辑  收藏  举报