CH2101 可达性统计

给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量。N,M≤30000。

输入格式
第一行两个整数N,M,接下来M行每行两个整数x,y,表示从x到y的一条有向边。

输出格式
共N行,表示每个点能够到达的点的数量。

题解:从点x出发能够到达的点构成的集合是f(x),有:
f(x)={x}U(U存在有向边(x,y) f(y)),
从x出发能够到达的点,是从“x的各个后继点y”出发能够到达的点的并集,再并上x自身。可以按照拓扑序的倒序进行计算。集合的并集计算可以利用状态压缩,用一个N位的二进制数表示可达的节点,bitset做一个或运算即可。

#include <iostream>
#include <bitset>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn = 30000+5;
int n,m,cnt=0;
int n1,n2;
bitset<maxn> bs[maxn];
int ver[maxn],Next[maxn],head[maxn],deg[maxn],a[maxn];
int tot=0;
void add(int x,int y){
	ver[++tot]=y,Next[tot]=head[x],head[x]=tot;
	deg[y]++;
}
void topsort(){
	queue<int> q;
	for(int i=1;i<=n;i++){
		if(deg[i] == 0) q.push(i);
	}
	while(q.size()){
		int x = q.front(); q.pop();
		a[++cnt] = x;
		for(int i=head[x];i;i=Next[i]){
			int y = ver[i];
			if(--deg[y]==0) q.push(y);
		}
	}
}
int main() {
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&n1,&n2);
		add(n1,n2);
	}
	topsort();
	for(int i=cnt;i>0;--i){
		int x = a[i];
		bs[x][x]=1;
		for(int j=head[x];j;j=Next[j]){
			int y=ver[j];
			bs[x]=bs[x]|bs[y];
		}
	}
	for(int i=1;i<=n;i++){
		cout<<bs[i].count()<<endl;
	}
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值