AtCoder Beginner Contest 401 E题 题解

E - Reachable Sethttp://E - Reachable Set

题意概述 :

给定一个无向图,

对于每个  k=1\sim n,解决以下问题:

-选择最少的一些顶点,使得删除这些顶点及其关联的所有边后 点1能到达1 \sim k以内的所有


牵制芝士 :头文件,建图,带权并查集


题解 :

首先,我们可以将题目拆成两部分

1 :判断一个点能不能实现目标

2 :对于能实现的点,计算答案


第一部分 :

可以用并查集来处理

只与比k小的节点连边,并统计与1所在集合的节点数

由于只与比k小的节点连边,所以集合中只会有小于等于k的节点

所以当且仅当点1所在集合的节点数等于k时,点1才会与1\sim k都联通

第二部分 :

使用vis数组标记目前是否能从1\sim k直接扩展到点x

ans表示vis值为1的节点的个数

所有大于k能扩展点,都需要被删除

因为只处理能实现目标的节点,所以答案就是ans-k

代码 :

#include<bits/stdc++.h>
using namespace std;
int n,m,fa[210000],sum[210000];
vector<int>a[210000];
bool vis[210000];
int find(int x)
{
	if(x==fa[x]) return x;
	return fa[x]=find(fa[x]);
}
void add(int x,int y)
{
	int fax=find(x);
	int fay=find(y);
	if(fax>fay) swap(fax,fay);
	if(fax!=fay)
	{
		sum[fax]+=sum[fay];
		fa[fay]=fax;
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;
		sum[i]=1;
	}
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		a[x].push_back(y);
		a[y].push_back(x);
	}
	vis[1]=1;
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<a[i].size();j++)
		{
			if(a[i][j]<i) add(a[i][j],i);//第一部分
			if(!vis[a[i][j]]) ans++;//第二部分
			vis[a[i][j]]=1;
		}
		printf("%d\n",sum[1]!=i?-1:(ans-i));
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值