Codeforces 1108F MST Unification

题目

https://codeforces.com/contest/1108/problem/F

题目大意

给你一个连通图,你可以进行若干次操作,每次操作能把一条边的边权+1。问你使这个图的最小生成树的方案唯一,所需要的的最少操作数。
点数、边数最大为2e5。

题解

看到最小生成树,很容易想到Kruskal。
把边权排序,将边权相同的点取出来,删去没有用的边(加入图中就会形成环)。
那么现在如果最小生成树方案不唯一,必定是因为在图中加入这堆边后会形成环。
发现删去某些新加入的在环中的边就可以了,于是把这些边的边权+1即可(连接剩下的边后,这些边就是没有用的,可以忽视)

CODE

#include<algorithm>
#include<cstdio>
using namespace std;
#define N 200005
struct edge{
    
    int x,y,len;}a[N];int f[N];
bool cmp(edge x,edge y){
    
    return x.len<y.len;}
int getf(int k){
    
    return f[k]==k?k:f[k]=getf(f[k]);}
int main()
{
    
    
	int n,m,i,j,k,cnt=0,ans=0,x,y;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;++i) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].len);
	sort(a+1,a+m+1,cmp);
	for(i=1;i<=n;++i) f[i]=i;
	for(i=1;i<=m&&cnt<n;i=k)
	{
    
    
		for(k=i;k<=m&&a[i].len==a[k].len;++k)
		{
    
    
			x=getf(a[k].x),y=getf(a[k].y);
			if(x==y) a[k].len=0;
		}
		for(j=i;j<k;++j) if(a[j].len)
		{
    
    
			x=getf(a[j].x),y=getf(a[j].y);
			x!=y?++cnt,f[x]=y:++ans;
		}
	}
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huangzihaoal/article/details/108651725
MST