POJ 2186:Popular Cows(tarjan算法入门题)

来源:互联网 发布:淘宝卖自己做的食品 编辑:程序博客网 时间:2024/05/29 07:37

题目链接:http://poj.org/problem?id=2186

题目意思:每一个牛的愿望是称为牛圈中最受欢迎的牛,在一个牛圈中共有N头牛,给出M对关系(A,B),

意思是牛A认为牛B很受欢迎,而且这种想法是会传递的,如果A认为B很受欢迎,B认为C很受欢迎,那么

A就会认为C是受欢迎的。你的任务是计算有多少牛让其他所有牛都认为它是最受欢迎的。

题目是一个强连通算法的入门题目。根据题目描述,我们就可以知道应该给出的一个关系网是有环存在的,

不然也不必问多少只牛让其他所有牛认为它是受欢迎的。

比如下面一组数据:自己随便写的一个数据

8 9

1 2

2 3

3 4

4 5

5 3

5 6

6 7

7 8

8 6


画出来就是这个图,然后可以看出对于6,7,8这三个牛来说,除自身外的所有牛都觉得自己

受欢迎,因此最后答案就是3.


解题思路:首先是进行缩点,给各个连通分量给出一个编号,我们把一个连通分量中的点同意看

成一个点,并用这个编号表示,对此对于缩点后的图来说,必须只能有一个出度为0的点,如果

多余一个的话,不能存在一些牛使其他所有牛都认为自己受欢迎。则答案就是0,否则我们就把

出度为0的点所在的连通分量的点做一个统计,统计到的点的个数就是答案。


POJ这个题目数据弱了,好多人说算法写得不对也可AC,不过我觉得自己写的是没问题的,测试了

讨论区的数据,差不多也都过了,感觉自己写的应该是正确的算法。


#include <iostream>#include <stdio.h>#include <string.h>using namespace std;const int maxm = 600000;const int maxn = 200000;int head[maxn];       ///链表头节点int Stack[maxn];      ///栈bool inStack[maxn];   ///用来标记节点是否在栈中int belong[maxn];     ///各个顶点所属于的连通分量int dfn[maxn];        ///时间标记int low[maxn];        ///相当于并查集int outdegree[maxn];  ///统计顶点入度int edgeNumber,time,top,cnt;     ///time时间标记,top栈顶指针,cnt当前连通分量编号struct Edge{    int A;    int B;    int nex;}edge[maxm];void addEdge(int a,int b){    edge[edgeNumber].A = a;    edge[edgeNumber].B = b;    edge[edgeNumber].nex = head[a];    head[a] = edgeNumber++;}///强连通找各个连通分量所属的集合void tarjan(int a){    dfn[a] = low[a] = ++time;    Stack[++top] = a;    inStack[a] = true;    for(int i = head[a]; i != -1; i = edge[i].nex)    {        int b = edge[i].B;        if(!dfn[b])  ///没有被访问过        {            tarjan(b);            low[a] = min(low[a],low[b]);        }        else if(inStack[b])        {            low[a] = min(low[a],dfn[b]);        }    }    if(dfn[a] == low[a])    {        cnt++;        int temp;        do        {            temp = Stack[top--];            inStack[temp] = false;            belong[temp] = cnt;     ///当前顶点属于第cnt个连通分量        }while(temp != a);    }}void solve(int n,int m){    int a,b;    edgeNumber = 0;    memset(head,-1,sizeof(head));    for(int i = 1; i <= m; i++)    {        scanf("%d%d",&a,&b);        addEdge(a,b);    }    top = time = cnt = 0;    memset(dfn,0,sizeof(dfn));    memset(low,0,sizeof(low));    memset(outdegree,0,sizeof(outdegree));    for(int i = 1; i <= n; i++)        inStack[i] = false;    for(int i = 1; i <= n; i++)    {        if(dfn[i]==0)            tarjan(i);    }    for(int i = 0; i < edgeNumber; i++)    {        a = edge[i].A;        b = edge[i].B;        a = belong[a];        b = belong[b];        if(a != b)  ///不属于一个连通分量的话,我们统计出度            outdegree[a]++;    }    int num = 0;    int temp;    for(int i = 1; i <= cnt; i++)    {        if(outdegree[i]==0)        {            temp = i;            num++;        }    }    int ans = 0;    if(num == 1)  ///出度为1的点必须有且只能有一个    {        for(int i = 1; i <= n; i++)        {            if(belong[i] == temp)                ans++;        }    }    printf("%d\n",ans);}int main(){    int N,M;    while(~scanf("%d%d",&N,&M)) ///N头牛,M个关系    {        solve(N,M);    }    return 0;}



原创粉丝点击