• acwing 164. 可达性统计


    地址 https://www.acwing.com/problem/content/description/166/

    给定一张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

    解答

    算法1
    (暴力枚举)
    从暴力开始吧。
    就是bfs遍历各个点 再将能达到的点能达到的点再次加入。
    结果是毫无悬念的tle了。

    在朴素的暴力枚举的时候 隐隐感觉使用拓扑排序后,BFS能有效的减少层级
    而且反向搜索点的时候 后面搜索的点可以使用前面已经搜索了的点能达到的点记录
    问题在于 使用已经搜索后的记录 会有重复的点,如何去重? 我使用了set
    结果这种想法也tle了

    (拓扑排序 压缩)
    最后得出正确的解决方案是拓扑排序后使用bitset压缩
    c++代码

    #include <iostream>
    #include <vector>
    #include <queue>
    #include <bitset>
    
    using namespace std;
    
    vector<int> g[30010];
    vector<int> copyg[30010];
    int dIn[30010];
    bitset<30010> f[30010];
    int n, m;
    /*
    10 10
    3 8
    2 3
    2 5
    5 9
    5 9
    2 3
    3 9
    4 8
    2 10
    4 9
    */
    
    void solve()
    {
        queue<int> q;
        int i = 1;
        for ( i = 1; i < n; i++) {
            if (dIn[i] == 0) {
                q.push(i);
            }
        }
        for (int i = 0; i < 30010; i++) {
            copyg[i] = g[i];
        }
    
        vector<int> ans;
        while (q.size()) {
            int point = q.front();
            q.pop();
            ans.push_back(point);
    
            //抹掉该点 和该点发出的边
            for (auto& e : g[point]) {
                //减掉入度
                dIn[e]--;
                //如果入度为0  可以放入队列 进行下一次遍历
                if (dIn[e] == 0)
                    q.push(e);
            }
    
            g[point].clear();
        }
    
        for (int i = ans.size() - 1; i >= 0; i--) {
            int j = ans[i];
            f[j][j] = 1;
            for (int k = 0; k < copyg[j].size(); k++) {
                f[j] |= f[copyg[j][k]];
            }
        }
    
        for (int i = 1; i <= n; i++) {
            cout << f[i].count() << endl;
        }
    }
    
    int main()
    {
        cin >> n >> m;
        for (int i = 0; i < m; i++) {
            int a, b; cin >> a >> b;
            g[a].push_back(b);
            dIn[b]++;
        }
    
        solve();
    
    
    }
    
    作者:itdef
    链接:https://www.acwing.com/file_system/file/content/whole/index/content/585665/
    来源:AcWing
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    作 者: itdef
    欢迎转帖 请保持文本完整并注明出处
    技术博客 http://www.cnblogs.com/itdef/
    B站算法视频题解
    https://space.bilibili.com/18508846
    qq 151435887
    gitee https://gitee.com/def/
    欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    JDK源码学习之 java.util.concurrent.automic包
    本地工程引入maven工程的配置方式
    JAVA配置&注解方式搭建简单的SpringMVC前后台交互系统
    Spring常用注解简析
    HTTP/HTTPS GET&POST两种方式的实现方法
    【JS语法】作用域与绑定图示
    【编程范式】函数式基础图示
    【技术思维】写好你的博客
    在Nginx服务器上用Jenkins发布Vue/React代码的步骤
    React事件绑定总结
  • 原文地址:https://www.cnblogs.com/itdef/p/13126949.html
Copyright © 2020-2023  润新知