codeforces 1108 F. MST Unification(最小生成树)

题意:给你一个图,问至少给其中某些边加多少使其成为一个路径总长度不变的唯一的最小生成树。

题目:
http://codeforces.com/group/w1oiqifZbS/contest/1108/problem/F

思路:首先要明白冲突边(需要加长度的边)有什么条件
1.长度相等
2.连通的块相同
满足这两个条件就是冲突边,比赛的时候一直在思考怎么记录连通块相同然后做判断呢?发现很难实现,做了一个多小时还是 wa29,比赛之后看题解才知道这道题应该直接用kruskal算法生成最小生成树的原理来做,每次选择最小边加入,那么就可以这样思考
冲突边=长度相同的边—生成树需要的边。
而生成树需要的边恰好就是并查集joint的数量,这样算法特别容易实现。

#include<bits/stdc++.h>
#define fi first
#define se second
#define FOR(a) for(int i=0;i<a;i++)
#define sc(a) scanf("%d",&a)
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
using namespace std;

typedef long long ll;
typedef pair<int, int> P;
typedef pair<P, int> LP;
const ll inf = 1e17 + 10;
const int N = 1e6 + 10;
const ll mod = 1000000007;
const int base=131;

map<string, int>ml;



ll f[N], vis[N], po[N],num[N], t, n, m, x, y, k;
ll ex, ey, cnt, ans, sum, flag;
ll hs[N];
ll dp[N];

vector<int> v[N];
map<int,int> mp;
priority_queue<P> q;
priority_queue<P> tq;
string s;

int fid(int x)
{
	if(f[x]==x) return x;
	else return f[x]=fid(f[x]);
}

struct node
{
	int x,y,w;
}a[N];

bool cmp(node a,node b)
{
	return a.w<b.w;
}
int main()
{
	ios::sync_with_stdio ( false );
	cin.tie ( 0 );

	cin>>n>>m;
	for(int i=1;i<=n;i++) f[i]=i;
	for(int i=1;i<=m;i++)
	{
		cin>>x>>y>>k;
		a[i].x=x;
		a[i].y=y;
		a[i].w=k;
	}
	sort(a+1,a+m+1,cmp);

	int mx=0;
	for(int i=1;i<=m;)
	{
		int j=i;
		while(a[i].w==a[j].w) j++;
		cnt=0;
		for(int k=i;k<j;k++)
		{
			if(fid(a[k].x)!=fid(a[k].y)) cnt++;//总边数
		}
		for(int k=i;k<j;k++)
		{
			if(fid(a[k].x)!=fid(a[k].y))
			{
				f[fid(a[k].x)]=fid(a[k].y);
				cnt--;//减去需要的边
			}

		}
		ans+=cnt;//冲突=总-需要
		i=j;

	}
	cout<<ans<<endl;

}

猜你喜欢

转载自blog.csdn.net/weixin_42640692/article/details/86653174