POJ 2186 -- Popular Cows【强连通分支 && Tarjan缩点】

来源:互联网 发布:图像算法工程师前途 编辑:程序博客网 时间:2024/05/01 03:40

Popular Cows
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 27198 Accepted: 10963

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 31 22 12 3

Sample Output

1

Hint

Cow 3 is the only cow of high popularity. 

题意:每个奶牛有梦想成为牧群中最受奶牛仰慕的奶牛, 在牧群中, 有N头奶牛 给定M对有序对(A, B),表示A仰慕B。由于仰慕关系具有传递性,也就是说,如果A仰慕B,B仰慕C, 则A也仰慕C,计算牧群中受每头牛仰慕的奶牛数量

解析:

如果强连通分量中一头牛A受到强连通分量外另一头牛B的仰慕,则该强连通分量中的每一头牛都受到B的仰慕;

如果强连通分量中一头牛A仰慕强连通分量外的另一头牛B,则强连通分量中的每一头牛都仰慕B。


所以将【每个强连通分支】缩成一个点,记录每个【缩点】的出度,并构造新图。统计出度为0的【缩点】的个数,如果正好为1,则说明该【缩点】能被其他所有【缩点】走到。该【缩点】包含点的个数就是我们所求答案。


简化来说:

给出一个有向图,求一共有多少个点,满足这样的条件:所有其它的点都可以到达这个点。

强连通分支+缩点,然后统计每个【缩点】的出度,如果只有一个为0,则输出其内部点的个数,如果有多个为0,说明没有答案,输出0。

#include <cstdio>#include <cstring>#include <vector>#include <queue>#include <algorithm>#define maxn 10000 + 1000#define maxm 50000 + 5000using namespace std;int n, m;struct node {int u, v, next;};node edge[maxm];int head[maxn], cnt;int low[maxn], dfn[maxn];int dfs_clock;int Stack[maxn];bool Instack[maxn];int top;int Belong[maxn] , scc_clock;int out[maxn];void init(){cnt = 0;memset(head, -1, sizeof(head));}void addedge(int u, int v){edge[cnt] = {u, v, head[u]};head[u] = cnt++;}void getmap(){    while(m--){        int a, b;        scanf("%d%d", &a, &b);        addedge(a, b);    }}void tarjan(int u, int per){    int v;    low[u] = dfn[u] = ++dfs_clock;    Stack[top++] = u;    Instack[u] = true;    for(int i = head[u]; i != -1; i = edge[i].next){        v = edge[i].v;        if(!dfn[v]){            tarjan(v, u);            low[u] = min(low[v], low[u]);        }        else if(Instack[v]){            low[u] = min(low[u], dfn[v]);        }    }    if(dfn[u] == low[u]){        scc_clock++;        do{            v = Stack[--top];            Instack[v] = false;            Belong[v] = scc_clock;        }while(u != v);    }}void find(){    memset(low, 0, sizeof(low));    memset(dfn, 0, sizeof(dfn));    memset(Instack, false, sizeof(Instack));    memset(Belong, 0, sizeof(Belong));    dfs_clock = scc_clock = top = 0;    for(int i = 1; i <= n; ++i){        if(!dfn[i])            tarjan(i, i);    }}void suodian(){    for(int i = 1; i <= scc_clock; ++i)        out[i] = 0;    for(int i = 0; i < cnt; ++i){        int u = Belong[edge[i].u];        int v = Belong[edge[i].v];        if(u != v)            out[u]++;    }}void solve(){int ans = 0;int temp = 0;int i;    for(int i = 1; i <= scc_clock; ++i){        //printf("%d\n", out[i]);        if(out[i] == 0){        temp = i;        ans++;        if(ans > 1){        printf("0\n");        return ;}}    }    int num = 0;    for(int i = 1; i <= n; ++i){    if(Belong[i] == temp)    num++;    }    printf("%d\n", num);}int main (){while(scanf("%d%d", &n, &m) != EOF){        init();        getmap();        find();        suodian();        solve();}return 0;}


1 0
原创粉丝点击