zoukankan      html  css  js  c++  java
  • POJ1236-Network of Schools(Tarjan + 缩点)

    主题链接


    题意:给定一张有向图,问最少选择几个点能遍历全图。以及最少加入几条边使得有向图成为一个强连通图。

    思路:对于有向图而言,首先求出有几个强连通分量,之后将每一个强连通分量缩点,形成DAG。本题开头第一句就说图是连通的了。

    之后想要遍历整张图的话。仅仅要找出入度为0的点有几个,而加入边的数量就取决于全部点的出入度大小。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <stack>
    #include <algorithm>
    
    using namespace std;
    
    const int MAXN = 105;
    
    vector<int> g[MAXN];
    stack<int> s; 
    int pre[MAXN], lowlink[MAXN], sccno[MAXN], dfs_clock, scc_cnt;
    int n, in[MAXN], out[MAXN];
    
    void tarjan(int u) {
        pre[u] = lowlink[u] = ++dfs_clock; 
        s.push(u);
        for (int i = 0; i < g[u].size(); i++) {
            int v = g[u][i]; 
            if (!pre[v]) {
                tarjan(v); 
                lowlink[u] = min(lowlink[u], lowlink[v]);
            }
            else if (!sccno[v])
                lowlink[u] = min(lowlink[u], pre[v]);
        }
        if (lowlink[u] == pre[u]) {
            scc_cnt++; 
            int x = -1;
            while (x != u) {
                x = s.top(); 
                s.pop();
                sccno[x] = scc_cnt;
            }
        }
    }
    
    void find_scc() {
        memset(pre, 0, sizeof(pre));
        memset(sccno, 0, sizeof(sccno));
        memset(lowlink, 0, sizeof(lowlink));
        dfs_clock = scc_cnt = 0;
        for (int i = 1; i <= n; i++)
            if (!pre[i])
                tarjan(i);
    }
    
    int main() {
        while (scanf("%d", &n) != EOF) {
            int u;
            for (int i = 1; i <= n; i++) {
                g[i].clear();
                while (scanf("%d", &u) && u) 
                    g[i].push_back(u);
            }
    
            find_scc();
            if (scc_cnt == 1) {
                printf("1
    0
    "); 
                continue;
            }
            else {
                memset(in, 0, sizeof(in)); 
                memset(out, 0, sizeof(out)); 
                for (int u = 1; u <= n; u++) {
                    for (int i = 0; i < g[u].size(); i++) {
                        int v = g[u][i]; 
                        if (sccno[u] != sccno[v]) {
                            in[sccno[v]]++;  
                            out[sccno[u]]++;
                        }
                    }  
                } 
                int a = 0, b = 0;
                for (int i = 1; i <= scc_cnt; i++) {
                    if (in[i] == 0) a++; 
                    if (out[i]== 0) b++;  
                }
                int ans = max(a, b);
                printf("%d
    %d
    ", a, ans);
            }
        } 
        return 0;
    }


    版权声明:本文博客原创文章。博客,未经同意,不得转载。

  • 相关阅读:
    php7安装Memcached扩展
    php7安装
    结束进程
    openssl 编译
    boost 编译
    php 与 c++ openssl 加密通信
    iptables 端口转发
    获取进程及父进程的两种方式
    windows 下获取父进程pid
    CentOS 64位系统 yum安装32位软件包的方法
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4716335.html
Copyright © 2011-2022 走看看