zoukankan      html  css  js  c++  java
  • POJ1236 Network of Schools 缩点+强连通 学校软件网络 基础题

    /*
    *State: POJ1236 164K    32MS    C++    2735B
    *题目大意:
    *        给定一个n (n<=100)个点的有向图,问:
    *      Q1、最少需要选择多少个点,使得从这些点出发能遍历完整个图;
    *      Q2、最少需要添加多少条有向边,使得整个图成为连通图;
    *解题思路:
    *        用tarjan_scc缩点之后求入度为0的节点个数即可Q1,之后再算加最少的
    *        边使图构成强连通分量即可。算出度为0跟入度为0的数量的最大值。不管
    *        缩点后的图是否有连通分支。
    *注意:
    *        求加最少边变成强连通,只需算出度为0跟入度为0的数量的最大值即可。
    *        无论改图是否有连通分量,都一样,但要注意排除该图本身就是强连通图
    *        的可能性
    */
    View Code
    State: 160K    0MS    C++    2158B
    #include <iostream>
    #include <vector>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    
    const int MAXN = 105;
    vector<int> vec[MAXN];
    int dfn[MAXN], low[MAXN], inS[MAXN];
    int step, scc, id[MAXN], myS[MAXN], top;
    
    //缩点建有向无环图
    vector<int> sccvec[MAXN];
    int vst[MAXN];
    
    void addEdge(int u, int v)
    {
        vec[u].push_back(v);
    }
    
    void init()
    {
        top = 0;
        scc = 1;
        step = 0;
        for(int i = 0; i < MAXN; i++)
        {
            vst[i] = 0;
            sccvec[i].clear();
            id[i] = -1;
            inS[i] = 0;
            dfn[i] = low[i] = -1;
            vec[i].clear();
        }
    }
    
    void tarjan_scc(int n)
    {
        dfn[n] = low[n] = ++step;
        myS[top++] = n;
        inS[n] = 1;
        for(unsigned i = 0; i < vec[n].size(); i++)
        {
            int son = vec[n][i];
            if(dfn[son] == -1)
            {
                tarjan_scc(son);
                low[n] = min(low[n], low[son]);
            }
            else if(inS[son] == 1)
                low[n] = min(low[n], dfn[son]);
        }
        if(dfn[n] == low[n])
        {
            int tmp;
            do
            {
                tmp = myS[--top];
                id[tmp] = scc;
                inS[tmp] = 0;
            }while(top != 0 && tmp != n);
            scc++;
        }
    }
    
    void deal_scc(int n, int &sol1, int &sol2)
    {
        int in[MAXN] = {0}, out[MAXN] = {0};
        int inTree[MAXN] = {0};
        for(int i = 1; i <= n; i++)
        {
            for(unsigned j = 0; j < vec[i].size(); j++)
            {
                int u = i, v = vec[i][j];
                if(id[u] == id[v])
                    continue;
                else
                {
                    sccvec[id[u]].push_back(id[v]);
                    inTree[id[v]]++;
                    in[id[v]]++;
                    out[id[u]]++;
                }
            }
        }
        sol1 = 0;
        for(int i = 1; i < scc; i++)
        {
            if(inTree[i] == 0)
                sol1++;
        }
        
        //sol2
        int IN = 0, OUT = 0, other = 0;
        for(int i = 1; i < scc; i++)
        {
            if(in[i] == 0)
                IN++;
            if(out[i] == 0)
                OUT++;
        }
        if(scc <= 2)
            sol2 = 0;
        else
            sol2 = max(IN, OUT);
    }
    
    int main(void)
    {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
    #endif
    
        int n;
        while(scanf("%d", &n) == 1)
        {
            init();
            int u, v;
            for(int i = 1; i <= n; i++)
            {
                while(scanf("%d", &v), v)
                {
                    addEdge(i, v);
                }
            }
            for(int i = 1; i <= n; i++)
            {
                if(dfn[i] == -1)
                    tarjan_scc(i);
            }
            int sol1, sol2;
            deal_scc(n, sol1, sol2);
            printf("%d\n%d\n", sol1, sol2);
        }
        return 0;
    }
  • 相关阅读:
    Elementary Methods in Number Theory Exercise 1.5.2
    Elementary methods in number theory exercise 1.5.1 暨 重启C++之路:列出1到210的所有素数
    Elementary Methods in Number Theory Exercise 1.5.5
    《Elementary Methods in Number Theory》勘误
    Elementary Methods in Number Theory Exercise 1.5.2
    Elementary Methods in Number Theory Exercise 1.5.5
    Linux_我理解的逻辑地址、线性地址、物理地址和虚拟地址(补充完整了)
    寄存器和常用汇编指令
    Linux_AMD体系结构学习(内存模型)
    计算机是如何启动的?
  • 原文地址:https://www.cnblogs.com/cchun/p/2641082.html
Copyright © 2011-2022 走看看