1. 程式人生 > >POJ 2186 Popular Cows(圖論之強連通分量)

POJ 2186 Popular Cows(圖論之強連通分量)

強連通分量之於有向圖,與並查集之於無向圖,在概念上極其相似,都是尋找互相聯絡的小部分內容。

POJ 2186 Popular Cows

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. 
--------------------- 
 

思路:

第一道強連通分量題,照著白書寫的。

最後判斷拓撲排序最後一個強連通分量是否可行看到兩種方法,白書是對最後一個連通分量再逆向dfs一遍,驗證是否所有點都能到達;看到網上大多的解法是計算每個連通分量的出度,若當且僅當出度為0的只有1個才符合。

 

程式碼如下:

main.cpp

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 1e4+5;
vector<int> g[maxn];
vector<int> rg[maxn];
vector<int> vs;  // post order
bool used[maxn];
int top[maxn], du[maxn], n, m, k;

void dfs(int u)
{
    used[u] = true;
    for (int i = 0; i < g[u].size(); i++)
    {
        int v = g[u][i];
        if (!used[v])
        {
            dfs(v);
        }
    }
    vs.push_back(u);
}

void rdfs(int u, int k)
{
    used[u] = 1;
    top[u] = k;
    for (int i = 0; i < rg[u].size(); i++)
    {
        int v = rg[u][i];
        if (!used[v])
        {
            rdfs(v, k);
        }
    }

}

int scc()
{
    memset(used, 0, sizeof(used));
    vs.clear();
    for (int i = 1; i <= n; i++)
    {
        if (!used[i])
        {
            dfs(i);
        }
    }
    memset(used, 0, sizeof(used));
    k = 0;
    for (int i = vs.size()-1; i >= 0; i--)
    {
        if (!used[vs[i]])
        {
            rdfs(vs[i], k);
            k++;
        }
    }
    return k;
}

int main()
{
    while (cin >> n >> m)
    {
        for (int i = 1; i < maxn; i++)
        {
            g[i].clear();
            rg[i].clear();
        }
        for (int i = 1; i <= m; i++)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            g[u].push_back(v);
            rg[v].push_back(u);
        }
        int num = scc();
        int ans = 0, u;
        for (int i = 1; i <= n; i++)
        {
            if (top[i] == num-1)
            {
                u = i;
                ans++;
            }
        }

        // check out whether the last strong componets part of topological sorting
        // can be reached by every other vertices
        memset(used, 0, sizeof(used));
        rdfs(u, 0);
        for (int i = 1; i <= n; i++)
        {
            if (!used[i])
            {
                ans = 0;
                break;
            }
        }
        printf("%d\n", ans);
        continue;

        // check out whether the vertices has one out degree are only one in the strong componets
        memset(du, 0, sizeof(du));
        for (int i = 1; i < n; i++)
        {
            for (int j = 0; j < g[i].size(); j++)
            {
                if (top[i] != top[g[i][j]])
                {
                    du[top[i]]++;
                }
            }
        }
        int sum = 0;
        for (int i = 0; i < num; i++)
        {
            if (du[i] == 0)
            {
                sum++;
            }
        }
        if (sum == 1)
        {
            printf("%d\n", ans);
        }
        else
        {
            printf("0\n");
        }
    }


    return 0;
}

測試結果如下: