2021-08-10 SSL 模拟赛 T2

2021-08-10 SSL 模拟赛 T2

依旧是没有标题的一题
2021-08-10 SSL 模拟赛 T2_第1张图片
2021-08-10 SSL 模拟赛 T2_第2张图片
题面就不复制了,太长了。

思路:

显然,我们争取用最少的费用获取所有情报,那么每一条线路都必须是有用的,就是删掉这条线后将会出现一部分情报无法获得的情况。
那这不就是个最小生成树的模板题吗?
我们把派出一个人所需要的费用看做是向不存在图中的 0 号节点连一条边,那么这题就转化成了一道最小生成树的模板题。
我们用克鲁斯卡尔算法去解决。
最小生成树的实现就不写了,也比较简单,时间复杂度 O ( m ∗ l o g   m ) O(m*log~m) O(mlog m)

代码:

#include
#include
#include
#include
#include
#include
#define r register
#define rep(i,x,y) for(r ll i=x;i<=y;++i)
#define per(i,x,y) for(r ll i=x;i>=y;--i)
using namespace std;
typedef long long ll;
ll n,g[1010][1010],v[1010],top,f[1010];
ll MST,tot;
struct node
{
     
	ll x,y,k; 
}a[1010*1010];
bool cmp(node x,node y)
{
     
	return x.k<y.k;
}
ll find(ll x)//并查集之查找
{
     
	return x==f[x]?x:f[x]=find(f[x]);
}
void make(ll x,ll y)//合并集合
{
     
	x=find(x),y=find(y);
	if(x!=y) f[x]=y;
}
ll in() //快读
{
     
	ll res=0,f=1;
	char ch;
	while((ch=getchar())<'0'||ch>'9')
	 if(ch=='-') f=-1;
	res=res*10+ch-'0';
	while((ch=getchar())>='0'&&ch<='9')
	 res=res*10+ch-'0';
	return res*f;
}
int main()
{
     
	scanf("%lld",&n);
	rep(i,1,n)
	 rep(j,1,n)
	 {
     
	 	g[i][j]=in();
	 	a[++top].x=i;
	 	a[top].y=j;
	 	a[top].k=g[i][j];
	 }
	rep(i,1,n)
	{
     
		scanf("%lld",&v[i]);
		a[++top].x=0; a[top].y=i; a[top].k=v[i];
		a[++top].x=i; a[top].y=0; a[top].k=v[i];
	}
	rep(i,0,n) f[i]=i;
	sort(a+1,a+top+1,cmp); //最下生成树的排序
	rep(i,1,top)
	{
     
		ll x=a[i].x,y=a[i].y,val=a[i].k;
		if(find(x)!=find(y))
		{
     
			make(x,y);
			++tot;
			MST+=val;
			if(tot>=n) break ;
		}
	}
	printf("%lld",MST);
	return 0;
}

你可能感兴趣的:(图论,#,并查集,最小生成树)