zoukankan      html  css  js  c++  java
  • POJ2186 Popular Cows 题解 强连通分量入门题

    题目链接:http://poj.org/problem?id=2186
    题目大意:
    每头牛都想成为牛群中的红人。
    给定N头牛的牛群和M个有序对(A, B),(A, B)表示牛A认为牛B是红人;
    该关系具有传递性,所以如果牛A认为牛B是红人,牛B认为牛C是红人,那么牛A也认为牛C是红人。
    不过,给定的有序对中可能包含(A, B)和(B, C),但不包含(A, C)。
    求被其他所有牛认为是红人的牛的总数。

    题目分析(引自 https://www.cnblogs.com/violet-acmer/p/9740737.html):
    考虑以牛为顶点的有向图,对每个有序对(A, B)连一条从 A到B的有向边;
    那么,被其他所有牛认为是红人的牛对应的顶点,也就是从其他所有顶点都可达的顶点。
    虽然这可以通过从每个顶点出发搜索求得,但总的复杂度却是O(NM),是不可行的,必须要考虑更为高效的算法。
    假设有两头牛A和B都被其他所有牛认为是红人,那么显然,A被B认为是红人,B也被A认为是红人;
    即存在一个包含A、B两个顶点的圈,或者说,A、B同属于一个强连通分量。
    反之,如果一头牛被其他所有牛认为是红人,那么其所属的强连通分量内的所有牛都被其他所有牛认为是红人。
    由此,我们把图进行强连通分量分解后,至多有一个强连通分量满足题目的条件。
    而按前面介绍的算法进行强连通分量分解时,我们还能够得到各个强连通分量拓扑排序后的顺序;
    唯一可能成为解的只有拓扑序最后的强连通分量。
    所以在最后,我们只要检查这个强连通分量是否从所有顶点可达就好了。

    思路整理:
    1、首先,使用tarjan缩点;
    2、其次,检查是否所有点可达
    只需要确定是不是缩点后只有一个点的出度为0即可。
    如果只有一个点的出度为0,则答案为该点对应的强连通分量中的原图中的点的数量;
    否则,答案为 0。

    实现代码如下:

    #include <iostream>
    #include <vector>
    #include <stack>
    #include <cstring>
    using namespace std;
    const int maxn = 10010;
    int n, dfn[maxn], low[maxn], belong[maxn], idx, cnt;
    bool instk[maxn];
    stack<int> stk;
    vector<int> g[maxn];
    void tarjan(int u) {
        dfn[u] = low[u] = ++idx;
        instk[u] = true;
        stk.push(u);
        int sz = g[u].size();
        for (int i = 0; i < sz; i ++) {
            int v = g[u][i];
            if (!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else if (instk[v]) low[u] = min(low[u], dfn[v]);
        }
        if (dfn[u] == low[u]) {
            cnt ++;
            int v;
            do {
                v = stk.top();
                stk.pop();
                instk[v] = false;
                belong[v] = cnt;
            } while (u != v);
        }
    }
    void solve() {
        memset(dfn, 0, sizeof(dfn));
        memset(instk, 0, sizeof(instk));
        for (int i = 1; i <= n; i ++) if (!dfn[i]) tarjan(i);
    }
    int m;
    bool vis[maxn];
    int main() {
        cin >> n >> m;
        while (m --) {
            int u, v;
            cin >> u >> v;
            g[u].push_back(v);
        }
        solve();
        for (int u = 1; u <= n; u ++) {
            int sz = g[u].size();
            for (int i = 0; i < sz; i ++) {
                int v = g[u][i];
                if (belong[u] != belong[v]) {
                    vis[ belong[u] ] = true;
                }
            }
        }
        int cc = 0, id = -1;
        for (int i = 1; i <= cnt; i ++) if (!vis[i]) {
            cc ++;
            id = i;
        }
        if (cc != 1) {
            cout << 0 << endl;
            return 0;
        }
        int ans = 0;
        for (int i = 1; i <= n; i ++) if (belong[i] == id) ans ++;
        cout << ans << endl;
        return 0;
    }
    
  • 相关阅读:
    20.multi_case04
    Linux 性能监测:Memory
    Linux 性能监测:介绍
    Linux 性能监测:CPU
    服务器压力上不去原因分析
    Oracle数据库shutdown immediate被hang住的几个原因
    性能测试需求指标分析方法
    关于spotlight for Windows和spotlight for oracle的使用
    Oracle性能监控脚本(sql)
    Oracle 常用性能监控SQL语句
  • 原文地址:https://www.cnblogs.com/codedecision/p/11826547.html
Copyright © 2011-2022 走看看