连通图 poj2186 最受欢迎的牛(求最受欢迎的牛的数量)

  Popular Cows
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 27531   Accepted: 11077

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.

Source

 
本题题意时每个牛都可以仰慕求它的牛,而且仰慕关系可以互相传递
问最受欢迎的牛的数量有多少个
可以利用强联通的缩点法,最后求缩点之后的初度为0的点的数量,
注意一个问题就是:
如果没有出度为0的点,那么结果输出答案为0
下面提供了几组样例,主要注意的输出为0的点需要特别判断
解决该题目的模板同上面的那个解决学校之间传递数量文件关系的拿到题所用的模板都是一套模板,而且判断入度出度那里也咩有变化
ps::附上嗲吗
#include <string.h>
#include <stdio.h>
#define V    10500
#define E    50500

struct edge
{
    int to, next;
}Edge[E];
int head[V], e, n;

int indeg[V], outdeg[V]; //点的入度和出度数
int belong[V], low[V], dfn[V], scc, cnt;//dfn[]:遍历到u点的时间; low[]:u点可到达的各点中最小的dfn[v]
int S[V], top;
bool vis[V];//v是否在栈中

int addedge(int u, int v)
{
    Edge[e].to = v;
    Edge[e].next = head[u];
    head[u] = e++;
    return 0;
}
void tarjan(int u)
{
    int v;
    dfn[u] = low[u] = ++cnt;//开始时dfn[u] == low[u]
    S[top++] = u;//不管三七二十一进栈
    vis[u] = true;
    for (int i=head[u]; i!=-1; i=Edge[i].next)
    {
        v = Edge[i].to;
        if (dfn[v] == 0)//如果v点还未遍历
        {
            tarjan(v);//向下遍历
            low[u] = low[u] < low[v] ? low[u] : low[v];//确保low[u]最小
        }
        else if (vis[v] && low[u] > dfn[v])//v在栈中,修改low[u]
            low[u] = dfn[v];
    }
    if (dfn[u] == low[u])//u为该强连通分量中遍历所成树的根
    {
        ++scc;
        do
        {
            v = S[--top];//栈中所有到u的点都属于该强连通分量,退栈
            vis[v] = false;
            belong[v] = scc;
        } while (u != v);
    }

}

int solve(){
    scc = top = cnt = 0;
    memset(dfn, 0, sizeof(dfn));
    memset(vis, false, sizeof(vis));
    for (int u=1; u<=n; ++u)
        if (dfn[u] == 0)
            tarjan(u);
    return scc;
}

void count_deg()
{
    memset(indeg, 0, sizeof(indeg));
    memset(outdeg, 0, sizeof(outdeg));
    for (int u=1; u<=n; ++u)
        for (int i=head[u]; i!=-1; i=Edge[i].next)
        {
            int v = Edge[i].to;
            if (belong[u] != belong[v])
            {
                indeg[belong[v]]++;
                outdeg[belong[u]]++;
            }
        }
}

int main()
{
    int u, v, i;
    int m;
    while (~scanf("%d%d", &n,&m))
    {
        e = 0;
        memset(head, -1, sizeof(head));
        for (int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);    
                addedge(u, v);
        }
        solve();
            count_deg();

          int num=0,tmp;
        for(int i = 1; i <= scc; i++)  
        {  
            if(!outdeg[i])  
            {  
                num++;  
                tmp = i;  
            }  
                  
        }  
          int ans=0;
        if(num == 1)  
        {  
            for(int i = 1; i <= n; i++)  
            {  
                if(belong[i] == tmp)  
                    ans++;  
            }  
            printf("%d\n", ans);  
        }  
        else  
        {  
            printf("0\n");  
        }  

        
    }
    return 0;
}

 

posted @ 2015-09-04 11:34  柳下_MBX  阅读(227)  评论(0编辑  收藏  举报