AcWing 164. 可达性统计

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

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

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

数据范围
1<=n,m<=30000

输入样例:
10 10
3 8
2 3
2 5
5 9
5 9
2 3
3 9
4 8
2 10
4 9

输出样例:
1
6
3
3
2
1
1
1
1
1

题解 :拓扑排序适用于有向无环图(DAG),我们用拓扑排序对所有点进行排序,我们可以得到一个有顺序的序列(不是大小顺序,是优先顺序 )。

这样我们倒着枚举,排完序的序列最后一个数肯定出度为0,也就是只能自己指向自己,向前遍历,前一个数是基于他能够到达的后一个数决定的。

问题来了,我们如何计算呢,题目中给的内存空间为256M,如果我们开一个30000 * 30000的二维数组,1e6大约4M ,这个二维数组3600M炸内存了。
我们可以利用bitset函数进行位运算,bitset<30000> f[30000] f【i】代表每一个点,第二维代表是一个01串(二进制),int型可以代表32个二进制数(0代表到不了,1代表可以到),所以空间大约为(30000 * 30000)/(32 ) 约等于 120M (√)

二进制位运算可以避免重复 0 1得1 , 1 1 得1

前面的方案数由后面的方案书累加起来。

最后bitset可以直接输出这个01串中的1的个数

#include<iostream>
#include<cstring>
#include<queue> 
#include<algorithm>
#include<bitset>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=30010;
vector<ll> vec[maxn];
bitset<maxn> f[maxn];
ll top[maxn]={0},indeg[maxn]={0};
ll n,m;

void topsort()
{
	ll k=0;
	queue<ll> q;
	for(int i=1;i<=n;i++)
	{
		if(!indeg[i])
			q.push(i);
	}
	while(q.size())
	{
		ll x=q.front();
		q.pop();
		top[++k]=x;
		for(int i=0;i<vec[x].size();i++)
		{
			if(!--indeg[vec[x][i]])
				q.push(vec[x][i]);
		}
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		ll a,b;
		cin>>a>>b;
		vec[a].push_back(b);
		indeg[b]++;
	}
	topsort();

	for(int i=n;i>=1;i--)
	{
		ll k=top[i];
		f[k][k]=1;
		for(int i=0;i<vec[k].size();i++)
		{
			f[k]|=f[vec[k][i]];
		}
	}
	
	for(int i=1;i<=n;i++)
	{
		cout<<f[i].count()<<endl;
	}
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aaHua_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值