Week6 D - 数据中心 [csp 201812-4]

在这里插入图片描述在这里插入图片描述在这里插入图片描述

思路1

这个题干看起来比较复杂,但是细读后就能明白,这个题会给定一个图,我们要找一个图的最小生成树,这棵生成树要保证其中的最大边权最小(这种树叫做瓶颈生成树)。

可以证明,最小生成树一定是瓶颈生成树(反之不真)。因此,我们可以直接求最小生成树并找最大边权即可。

思路2

最小生成树或许不太容易想到,这个题也可以用二分答案的方法。给定一个最大边权的值,我们是容易判断是否存在生成树的(首先对所有边权排序,然后就比较容易)。而答案是最大边权的最小值,具有单调性,所以二分可行。

完整代码(求最小生成树)
#include<iostream>
#include<queue>
#define MAX 50005
using namespace std;
int pre[MAX];
int num[MAX];
int find(int x)
{
	if(pre[x] == x)	return x;
	return (pre[x] = find(pre[x]));
}
void unite(int x, int y)
{
	int fx = find(x);
	int fy = find(y);
	if(fx == fy)	return;
	if(num[fx] > num[fy])	swap(fx, fy);
	pre[fx] = fy;
	num[fy] += num[fx];
}
struct Edge{
	int u;
	int v;
	int t;
	bool operator < (const Edge &e) const
	{
		return (t > e.t);
	}
};
priority_queue<Edge> pq;
int main ()
{
	ios::sync_with_stdio(false);
	int n, m, root;
	cin>>n>>m>>root;
	for(int i=0;i<=n;i++)
	{
		pre[i]=i;
		num[i]=1;
	}
	for(int i=0;i<m;i++)
	{
		int u,v,t;
		cin>>u>>v>>t;
		pq.push({u,v,t});
	}
	int res=-1;
	int cnt=1;
	while(cnt < n)
	{
		Edge e;
		while(true)
		{
			e=pq.top(); pq.pop();
			if(find(e.u) != find(e.v))	break;
		}
		if(res < e.t)	res=e.t;
		unite(e.u, e.v);
		cnt++;
	}
	cout<<res<<endl;
	return 0;
}
完整代码(二分答案)
#include<bits\stdc++.h>
using namespace std;
int pre[50005];
int r[50005];
int find(int x)
{
	if(pre[x] == x)	return x;
	else return (pre[x] = find(pre[x]));
} 

void unite(int x, int y)
{
	int fx = find(x);
	int fy = find(y);
	if(fx == fy)	return;
	if(r[fx] > r[fy])	swap(fx, fy);
	pre[fx] = fy;
	r[fy] += r[fx];
}
int N, M, root;
struct Edge{
	int u;
	int v;
	int w;
	bool operator < (const Edge &e) const
	{
		return w < e.w;
	}
}e[100005];
bool check(int x)
{
	for(int i=1;i<=N;i++)	pre[i]=i, r[i]=1;
	int n=1;
	for(int i=0;i<M, e[i].w <=x;i++)
	{
		int fv = find(e[i].v);
		int fu = find(e[i].u);
		if(fv != fu)	unite(fv, fu), n++;
		if(n == N)	return true;
	}
	return false;
}
int binS()
{
	int l=0, r=1000001;
	int mid;
	while(l < r)
	{
		mid = l+r>>1;
		if(check(mid))	r = mid;
		else l = mid + 1; 
	}
	return r;
}
int main()
{
	cin>>N>>M>>root;
	for(int i=0;i<M;i++) cin>>e[i].u>>e[i].v>>e[i].w;
	sort(e, e+M);
	cout<<binS();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值