• acwing 164. 可达性统计(拓扑排序+位运算,bitset使用)


    题目传送门

    题目描述

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

    输入格式

    第一行两个整数 N,MN,M,接下来 MM 行每行两个整数 x,yx,y,表示从 xx 到 yy 的一条有向边。

    输出格式

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

    数据范围

    1≤N,M≤300001≤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
    

    拓扑排序+位运算

    分析

    使用了bitset

    1. 首先进行一次topo排序,记录拓扑排序的顺序

    2. 然后倒序遍历拓扑排序的顺序,对于逆序中每个点

      • 首先该点可以到达它自己

      • 然后记录该点能够到达其他的所有点(用bitset 加 或运算表示)

        • 遍历该点能到的所有点(邻接表),用bitset 加 或运算表示该点能到的所有点
    3. 然后遍历一遍所有点,看每个点能够到达点的数量(bitset中1的个数)

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue> 
    #include<algorithm>
    #include<bitset>
    using namespace std;
    const int N = 30010;
    const int M = N * 2;
    
    int h[N], e[M], ne[M], idx = 0;
    int d[N]; // 入度 
    int seq[N], cnt = 0; // 每个点到其他点的距离 
    
    bitset<N> f[N]; // 前面的N表示每个bitset的长度
    			    // 后面的N表示有N个bitset 
    
    void add(int a, int b)
    {
    	e[idx] = b;
    	ne[idx] = h[a];
    	h[a] = idx++;
    }
    int n, m;
    
    void topo()
    {
    	queue<int> q;
    	for(int i = 1; i <= n; i++)
    		if(!d[i]) 
    		{
    			seq[cnt++] = i;
    			q.push(i);
    		}
    		
    	
    	while(q.size())
    	{
    		int t = q.front();
    		q.pop();
    		
    		
    		
    		for(int i = h[t]; i != -1; i = ne[i])
    		{
    			int j = e[i];
    			if(!d[j]) continue;
    			
    			d[j]--;
    			if(!d[j])
    			{
    				seq[cnt++] = j;
    				q.push(j);
    			}
    		}
    	}
    }
    
    
    int main()
    {	
    	scanf("%d%d", &n, &m);
    	memset(h, -1, sizeof(h));
    
    	while(m --)
    	{
    		int x, y;
    		scanf("%d%d", &x, &y);
    		add(x, y); 
    		d[y]++; // 入度++
    	} 
    	
    	topo();
    	
    	// 倒序遍历topo排序 
    	for(int i = n-1; i >= 0; i--) 
    	{
    		
    		int j = seq[i]; // j: 1 -> n中某个数 
    		
    		f[j][j] = 1; // j点的第j位为1
    		for(int k = h[j]; k != -1; k = ne[k])
    		{
    			f[j] |= f[e[k]]; // j点能到的所有点包括其指向的点能到的点的并集	
    		} 
    	}
    	
    	for(int i = 1; i <= n; i++) printf("%d\n", f[i].count());
    	return 0; 
    }
    
    

    时间复杂度

    参考文章

    https://www.acwing.com/solution/content/32117/

  • 相关阅读:
    UVALive4973 CERC2010A Ardenia
    HDU4116 Fruit Ninja (2011 Asia ChengDu Regional Contest)
    POJ1030 Rating
    HDU2471 2008 Asia Regional Hangzhou History of Languages
    UVA12304_2D Geometry 110 in 1!
    UVALive4974 CERC2010B Beasts
    2012CSU_ACM集训中期检测 简要题解
    关于ACM,2010开始的一些故事
    UVA12302 NinePoint Circle
    System.Web.HttpRequestValidationException:解决方法
  • 原文地址:https://www.cnblogs.com/VanHa0101/p/16014880.html
Copyright © 2020-2023  润新知