Popular Cows(强连通分量 + Tarjan)

Popular Cows
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 22190   Accepted: 9077

Description

Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is 
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow. 

Input

* Line 1: Two space-separated integers, N and M 

* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular. 

Output

* Line 1: A single integer that is the number of cows who are considered popular by every other cow. 

Sample Input

3 3
1 2
2 1
2 3

Sample Output

1

Hint

Cow 3 is the only cow of high popularity. 

      题意:

      给出 N(1 ~ 10000) 头牛 ,和 M (1 ~ 50000)种崇拜关系。后给出这 M 种崇拜关系,若 A 崇拜 B,B 崇拜 C,那么 A 也会崇拜 C,求出所有牛都认同的牛的总数。

 

       思路:

       强连通分量。求出最后到达的强连通分量的结点数,再判断这个强连通分量是否其他所有点都能到达。注意 Tarjan 算法首先算出的第一个强连通分量即为最后一个强连通分量。判断这个强连通分量是否其他所有点都能到达,那么将这个图反向保存,找出这个强连通分量中的其中一个点,由此点出发,判断是否遍历到了所有的点即可,若不能到达,说明这个没有这样的牛存在,输出 0。

 

      AC:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <stack>

using namespace std;;

const int EMAX = 50005;
const int NMAX = 10005;

int n, m, ind, iind;
int v[EMAX], fir[NMAX], next[EMAX];
int iv[EMAX], ifir[NMAX], inext[EMAX];

int scc_cnt, dfs_clock, k;
int pre[NMAX], cmp[NMAX], low[NMAX];
int vis[NMAX];
stack<int> s;

void add_edge (int f, int t) {
        v[ind] = t;
        next[ind] = fir[f];
        fir[f] = ind;
        ++ind;
}

void i_add_edge (int f, int t) {
        iv[iind] = t;
        inext[iind] = ifir[f];
        ifir[f] = iind;
        ++iind;
}

void dfs (int u) {
        pre[u] = low[u] = ++dfs_clock;
        s.push(u);
        for (int e = fir[u]; e != -1; e = next[e]) {
                if (!pre[ v[e] ]) {
                        dfs(v[e]);
                        low[u] = min (low[u], low[ v[e] ]);
                } else if (!cmp[ v[e] ]) {
                        low[u] = min (low[u], pre[ v[e] ]);
                }
        }

        if (low[u] == pre[u]) {
                ++scc_cnt;
                for(;;) {
                        int x = s.top(); s.pop();
                        cmp[x] = scc_cnt;
                        if (x == u) break;
                }
        }
}

void scc() {
        dfs_clock = scc_cnt = 0;
        memset(pre, 0, sizeof(pre));
        memset(cmp, 0, sizeof(cmp));

        for (int u = 1; u <= n; ++u) {
                if (!pre[u]) dfs(u);
        }
}

void dfs_all (int u) {
        vis[u] = 1;
        for (int e = ifir[u]; e != -1; e = inext[e])
                if(!vis[ iv[e] ]) dfs_all( iv[e] );
}

int main () {

        ind = iind = 0;
        scanf("%d%d", &n, &m);
        memset(fir, -1, sizeof(fir));
        memset(ifir, -1, sizeof(ifir));
        while (m--) {
                int f, t;
                scanf("%d%d", &f, &t);
                add_edge(f, t);
                i_add_edge(t, f);
        }

        scc();

        int ans = 0, left = 0, no;
        for (int u = 1; u <= n; ++u) {
                if (cmp[u] == 1) {
                        ++ans;
                        no = u;
                }
        }

        int k = 0;
        memset(vis, 0, sizeof(vis));
        dfs_all(no);

        for (int u = 1; u <= n; ++u)
                if (vis[u]) ++k;

        if(k == n) printf("%d\n", ans);
        else printf("0\n");

        return 0;
}

 

你可能感兴趣的:(tar)