poj2186-Popular Cows(Tarjan求强连通分量+缩点)

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头牛,输入 a,b代表a崇拜b,崇拜是有传递性的,如果a->b,b->c,那么a->c

问,有多少头牛,被所以除了它本身的牛所崇拜~

 

求出每一个强连通分量,缩为一点,构造新的图,在新的图中,找出出度为0的点,当出度为0的点有且只有一个的时候,然后看这个点内有多少个子节点,这个数量即为最后的答案。如果出度为0的点不是1个,那么答案为0.

 

下面证明抄自别的博客

证明:

      如果有强连通分量被孤立(即和其他强连通分量无边相连),那么答案一定是0,此时由于缩点后是一个DAG图,出度为0的点的个数一定大于1.

      如果没有点被孤立,当出度为0的点多于1个时,由DAG图的性质可得,一定不存在一个点能从其他所有点到达。只有当出度为0的点的个数等于1时,这个出度为0的点才能被其他所有点到达。


举个栗子:

样例  

1 2

2 1

2 3

有两个强连通分量{1,2},{3}

这时候把{1,2}缩为一个点,指向3,说明3被1,2所崇拜。强连通分量{3}里面只有一个3,故ans=1

假如再加两条边(输入的n变为4)

3 4

4 3

这时候有两个强联通分量 {1,2},{3,4}

这时候把{1,2}缩为一个点x,{3,4}缩为一个点y, x->y,因为每一个强连通分量里面的所有点都互相仰慕,所以{3,4}里面的两个点都符合条件,故ans=2.

 

(在disguss翻到好多免费的测试样例~~~)

#include
#include
#include
#include
#include
#include
#define memset(a,v)  memset(a,v,sizeof(a))
#define eps 1.0E-8
using namespace std;
const int MAXL(5*1e4);
const int INF(0x3f3f3f3f);
const int mod(1e9+7);
typedef long long int LL;
struct node
{
    int to,next;
} edge[MAXL+50];
int head[MAXL+50];
int DFN[MAXL+50];//节点u搜索的序号(时间戳)
int LOW[MAXL+50];//u或u的子树能够追溯到的最早的栈中节点的序号(时间戳)
int Belong[MAXL+50];//n:点的个数;m:边的条数
int instack[MAXL+50];//标记点是否在栈中
int stack[MAXL+50];
int top,Bcnt;//top:栈的顶点标记 Bcnt:强连通分量的个数
int index;//序号(时间戳)
int cnt;
int outdegree[MAXL+50];
int n,m;
void addedge(int u,int v)
{
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void Tarjan(int u)
{
    DFN[u]=LOW[u]=++index;
    instack[u]=true;
    stack[++top]=u;
    for(int i=head[u]; ~i; i=edge[i].next)
    {
        int v=edge[i].to;
        if( !DFN[v] )
        {
            Tarjan(v);
            LOW[u]=min(LOW[u],LOW[v]);
        }
        else if( instack[v] && DFN[v]

 

你可能感兴趣的:(图论)