• POJ 1236 Network of Schools (强连通分量缩点求度数)


    题意:

    求一个有向图中:

    (1)要选几个点才能把的点走遍

    (2)要添加多少条边使得整个图强联通

    分析:

    对于问题1, 我们只要求出缩点后的图有多少个入度为0的scc就好, 因为有入度的scc可以从其他地方到达。

    对于问题2, 每个入度为0的scc, 都可以补一条边可以变成强连通图, 每个出度为0的scc, 也可以补一条边使其变成强连通图。 所以答案就是max(入度为0scc个数,出度为0scc个数)。

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<cstring>
    #include<string>
    #include<sstream>
    #include<map>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<cmath>
    #define mem(a) memset(a, 0, sizeof(a))
    #define rep(i,a,b) for(int i = a; i < b; i++)
    #define _rep(i,a,b) for(int i = a; i <= b; i++)
    using namespace std;
    const int maxn = 107;
    vector<int> G[maxn];
    int n, m, Index = 1, scc_cnt = 0;
    int dfn[maxn], low[maxn], vis[maxn], scc[maxn];
    int in_deg[maxn], out_deg[maxn];
    stack<int> s;
    void tarjan(int u){
        dfn[u] = Index;
        low[u] = dfn[u];
        Index++;
    
        vis[u] = 1;
        s.push(u);
        for(int i = 0; i < G[u].size(); i++){
            int v = G[u][i];
            if(!dfn[v]){
                tarjan(v);
                low[u] = min(low[v], low[u]);
    
            }else if(vis[v]){
                low[u] = min(low[u], dfn[v]);
            }
        }
        if(dfn[u] == low[u]){
            vis[u] = 0;
            scc[u] = scc_cnt;
            int t;
            for(;;){
                int t = s.top(); s.pop();
                scc[t] = scc_cnt;
                vis[t] = 0;
                if(t == u) break;
            }
            scc_cnt++;
        }
    }
    int main(){
        while(~scanf("%d", &n)){
            _rep(i,1,n) G[i].clear();
            mem(dfn), mem(low), mem(vis), mem(scc), mem(in_deg), mem(out_deg);
            Index = 1, scc_cnt = 0;
            _rep(i,1,n){
                int v;
                while(scanf("%d", &v) && v){
                    G[i].push_back(v);
                    m++;
                }
            }
            
            _rep(i,1,n){
                if(!dfn[i]) tarjan(i);
            }
            _rep(u,1,n) rep(i,0,G[u].size()){//缩点,枚举每条边, 如果不在同一个scc说明这是新图中的一条边
                int v = G[u][i];
                if(scc[u] != scc[v]){
                    out_deg[scc[u]]++, in_deg[scc[v]]++;
                }
            }
            int _0in = 0, _0out = 0; //入度为0的scc , 出度为0的scc
            rep(i,0,scc_cnt){
                if(in_deg[i] == 0) _0in++;
                if(out_deg[i] == 0) _0out++;
            }
            if(scc_cnt > 1)
            printf("%d
    %d
    ", _0in, max(_0in,_0out)); //
            else printf("1
    0
    ");//特判一下只有一个scc的情况, 那么只用选一个点
        }
        return 0;
    }
  • 相关阅读:
    《JavaScript高级程序设计》读书笔记 14章
    C# 程序集是啥
    C#之反射又是什么东西
    C#版 大数计算器加法
    C#版 大数计算器乘法
    我所认识的三层
    《JavaScript高级程序设计》读书笔记 56章
    C# 委托加深理解
    C#版 大数计算器减法
    C# 事件到底是什么
  • 原文地址:https://www.cnblogs.com/Jadon97/p/8360564.html
Copyright © 2020-2023  润新知