POJ 2553 The Bottom of a Graph(Tarjan)

题意:

给定有向图,找出图中所有满足条件的点 v,保证所有从 v 出发的都能回到 v。 

思路:

1. Tarjan + 缩点:缩点之后统计出所有出度为 0 的点;

2. 于是这个出度为 0 的强连通分量的所有点都是满足题意的点。

 

#include <iostream>

#include <vector>

#include <stack>

#include <algorithm>

using namespace std;



const int MAXN = 5010;

vector<int> G[MAXN];

stack<int> S;

int dfn[MAXN], low[MAXN], sccno[MAXN], sccnum, tclock;

int indeg[MAXN], outdeg[MAXN];



void tarjan(int u) {

    dfn[u] = low[u] = ++tclock;

    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[u], low[v]);

        } else if (!sccno[v]) {

            low[u] = min(low[u], dfn[v]);

        }

    }



    if (dfn[u] == low[u]) {

        sccnum += 1;

        int v = -1;

        while (v != u) {

            v = S.top();

            S.pop();

            sccno[v] = sccnum;

        }

    }

}



void findscc(int n) {

    for (int i = 0; i <= n; i++)

        dfn[i] = low[i] = sccno[i] = 0;

    sccnum = tclock = 0;

    for (int i = 1; i <= n; i++)

        if (!dfn[i]) tarjan(i);

}



int main() {

    int n, e;

    while (scanf("%d", &n) && n) {

        scanf("%d", &e);

        for (int i = 1; i <= n; i++)

            G[i].clear();

        for (int i = 0; i < e; i++) {

            int u, v;

            scanf("%d%d", &u, &v);

            G[u].push_back(v);

        }

        findscc(n);

        for (int i = 1; i <= n; i++)

            indeg[i] = outdeg[i] = 0;

        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]) {

                    indeg[sccno[v]] += 1;

                    outdeg[sccno[u]] += 1;

                }

            }

        }

        for (int i = 1; i <= n; i++) {

            if (!outdeg[sccno[i]]) 

                printf("%d ", i);

        }

        printf("\n");

    }

    return 0;

}

你可能感兴趣的:(Graph)