题目链接:http://poj.org/problem?id=2186
Popular Cows
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 21572 | Accepted: 8819 |
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.
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.
* 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
题目大意:N头奶牛,给出若干个欢迎关系A B,表示A欢迎B,欢迎关系是单向的,但是是可以传递的。另外每个奶牛都是欢迎他自己的。求出被所有的奶牛欢迎的奶牛的数目。
奶牛数目N≤10000
直接的欢迎关系数目M≤50000
题解:
数据量太大,直接搞肯定行不通,如果A欢迎B,我们就连一条从A到B的有向边。容易发现,在同一个强连通分量里的点具有同样的“受欢迎程度”:能够到达它们的点集是相同的,从它们出发能够到达的点集也是相同的。所以我们把强连通缩点,最后扫描求出
出度为0的点个数,如果是1就说明这个顶点(也可能是收缩的点)即为所求答案,否则为0。
tarjan看了几天才大概看懂,。缩点参考的是http://www.myexception.cn/program/1449753.html这篇文章
有一个数组belong[MAX]来染色,belong[i] =scc 就表示 i 这个元素属于第scc个强连通分量,在把所有的点求完强连通分量之后,我们只是得到一个所有点的归属数组Belong[MAX],那么,之后我们就用两个数组 in[MAX],out[MAX]表示缩点后的有向无环图的点的入度和出度
具体代码如下:
/**
* @author neko01
*/
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
using namespace std;
typedef long long LL;
#define INF 100000000
const double pi=acos(-1.0);
const double eqs=1e-10;
int head[10005];
int dfn[10005];
int low[10005];
int belong[10005]; //节点i属于哪个强连通
int num[10005]; //强连通i的节点数
int stack[10005];
int vis[10005]; //vis[i]=1表示在栈中
int out[10005];
int cnt,top,scc;
int n,m;
struct edge{
int to;
int next;
}a[50005];
void add(int u,int v)
{
a[cnt].to=v;
a[cnt].next=head[u];
head[u]=cnt++;
}
void tarjan(int u)
{
dfn[u]=low[u]=++cnt;
stack[++top]=u;
vis[u]=1;
for(int i=head[u];i!=-1;i=a[i].next)
{
int v=a[i].to;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v]) //回边
{
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]) //根
{
scc++;
int t;
do
{
t=stack[top--];
vis[t]=0;
num[scc]++;
belong[t]=scc;
}while(u!=t);
}
}
void solve()
{
cnt=top=scc=0;
for(int i=1;i<=n;i++)
{
if(!dfn[i])
tarjan(i);
}
int ans=0,k=1;
for(int i=1;i<=n;i++)
{
for(int j=head[i];j!=-1;j=a[j].next)
{
int v=a[j].to;
if(belong[v]!=belong[i])
out[belong[i]]++;
}
}
for(int i=1;i<=scc;i++)
if(out[i]==0)
ans++,k=i;
if(ans==1)
printf("%d\n",num[k]);
else
printf("0\n");
}
int main()
{
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
solve();
return 0;
}