可达性统计

题目:

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

思路:

采用邻接表存图的方式,然后对这张图中节点进行拓扑排序,排序完成后能够得到一个拓扑序列,对于拓扑序列中任意一条边(x,y),x都在y之前出现。倒序遍历拓扑序列中的点,设集合f[i]为第i个点能到达的点的状态(压缩成二进制最大就是30000位二进制)

f[i]=集合{f[a],f[b],f[c],...f[z]}(a,b....z为i拓扑序列后面的节点)的并集

就相当于f[i]分别或(|)上f[a],f[b]....f[z]

这个操作可以利用bitset库,将N位二进制数压缩成N/32+1个unsigned int

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3e4+10;
int n,m;//n个点,m条边
int e[N],ne[N],head[N],idx;//存储邻接表
int ind[N],top_arr[N];//入度,拓扑排序序列
bitset<N>f[N];
//二进制(1代表能够到达,0代表不能)记录当前点能够到达的点
void add(int x,int y){//邻接表加边
	e[idx]=y;ne[idx]=head[x];head[x]=idx++;
}

void topsort(){//拓扑排序
	queue<int> q;
	for(int i=1;i<=n;i++){
		if(ind[i]==0){
			q.push(i);
		}
	}
	int cnt=0;
	while(q.size()){
		int p=q.front();q.pop();
		top_arr[++cnt]=p;
		for(int i=head[p];i;i=ne[i]){
			int j=e[i];
			if(--ind[j]==0)q.push(j);
		}
	}
}

int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		ind[y]++;//入度
		add(x,y);//加边
	}
	topsort();
	for(int i=n;i>=1;i--){//倒序遍历拓扑序列中的点
		int now=top_arr[i];
		f[now][now]=1;//对于当前节点now它本身肯定是能够到达自己的
		for(int j=head[now];j;j=ne[j]){//当前点所连接的点
			f[now]|=f[e[j]];//求并集
		}
	}
	for(int i=1;i<=n;i++)printf("%d\n",f[i].count());
 	return 0;
}



总结:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值