Popular Cows
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 19297 | Accepted: 7767 |
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备受注目,而奶牛B也可能认为奶牛C备受注目。奶牛们的这种“认为”是单向可传递的,就是说若奶牛A认为奶牛B备受注目,但奶牛B不一定会认为奶牛A备受注目。而当A认为B备受注目,且B认为C备受注目时,A一定也认为C备受注目。
思路:强连通+缩点
解题思路:首先,在一个有向无环图中,能被所有点达到点,出度一定是0。
先求出所有的强连通分支,然后把每个强连通分支收缩成一个点。这样,这个有向图就变成了一个有向无环图。在这个新的图中,只需知道出度为0的点有几个。如果
出度为0的点超过1个,则输出0;不然就输出出度为0的那个点所代表的那个强连通分支含有的顶点数即可。
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stack>
#include<vector>
#include<iostream>
#define max 10005
using namespace std;
int vis[max];
int belong[max];//记录节点属于哪一个强连通分量
int dfn[max],low[max];
int num[max];//记录一个强连通分量含有节点的数目
vector<int>gra[max];
stack<int>s;
int index;
int id;//记录强连通分量的个数及编号
int n,m;
void tarjan(int pos)
{
int i;//在i若定义成全局变量就wa,为保险起见 若函数内部和main函数用到同样的变量名(如i)在函数内部和main函数分别定义
dfn[pos]=low[pos]=++index;
vis[pos]=1;
s.push(pos);
for(i=0;i<gra[pos].size();i++)
{
int next=gra[pos][i];
if(!dfn[next])
{
tarjan(next);
low[pos]=min(low[pos],low[next]);
}
else
if(vis[next]==1)
{
low[pos]=min(low[pos],dfn[next]);
}
}
if(dfn[pos]==low[pos])
{
id++;
while(1)
{
int t=s.top();
belong[t]=id;
//vis[t]=1;
s.pop();
num[id]++;
if(t==pos)
break;
}
}
}
int main()
{
int a,b;
int i,j;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(vis,0,sizeof(vis));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(num,0,sizeof(num));
memset(belong,0,sizeof(belong));
for(i=0;i<max;i++)
{
gra[i].clear();
}
while(!s.empty())
{
s.pop();
}
for(i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
gra[a].push_back(b);
}
index=id=0;//初始化不能忘
for(i=1;i<=n;i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
memset(vis,0,sizeof(vis));//vis数组再次清零
for(i=1;i<=n;i++)
{
for(j=0;j<gra[i].size();j++)
{
if(belong[i]!=belong[gra[i][j]])//两个点不属于同一个强连通分量
{
vis[belong[i]]=1;//两点不属于同一个强连通分量,一个强连通分量的一点i指向一点j,则i出度不为零,又因为强连通分量里面的点两两之间都有路径,所以此强连通分量所有的点都有到j的路径,即整个强连通分量的点出度都不为零
break;
}
}
}
int outnum=0,location;
for(i=1;i<=id;i++)
{
if(vis[i]==0)
{
outnum++;
location=i;
}
}
if(outnum==1)
{
printf("%d\n",num[location]);
}
else
printf("0");
}
}