[poj 2186]Popular Cows[Tarjan强连通分量]

时间:2023-03-09 08:26:55
[poj 2186]Popular Cows[Tarjan强连通分量]

题意:

有一群牛, a会认为b很帅, 且这种认为是传递的. 问有多少头牛被其他所有牛认为很帅~

思路:

关键就是分析出缩点之后的有向树只能有一个叶子节点(出度为0).

做法就是Tarjan之后缩点统计出度.

#include <cstdio>
#include <cstring>
#include <stack>
#include <algorithm>
using namespace std;
const int MAXN = 10005;
const int MAXE = 50005;
struct pool
{
int v,pre;
}p[MAXE];
int num,head[MAXN];
int dfn[MAXN],low[MAXN],id[MAXN],dag[MAXN];
bool vis[MAXN];
int size,Index,n,m;
stack<int> s;
void add(int u, int v)
{
p[++num].v = v;
p[num].pre = head[u];
head[u] = num;
} void Tarjan(int u)
{
low[u] = dfn[u] = ++Index;
vis[u] = true;
s.push(u);
for(int tmp = head[u],k;k = p[tmp].v,tmp;tmp = p[tmp].pre)
{
if(!dfn[k])
{
Tarjan(k);
low[u] = min(low[u],low[k]);
}
else if(vis[k])
low[u] = min(low[u],low[k]);
}
if(dfn[u]==low[u])
{
size++;
int k;
do
{
k = s.top();s.pop();
vis[k] = false;
id[k] = size;
}while(k!=u);
}
} void shrink()
{
for(int i=1;i<=n;i++)
for(int tmp = head[i],k;k = p[tmp].v,tmp;tmp = p[tmp].pre)
if(id[i]!=id[k])
dag[id[i]]++;//缩点
} int main()
{
scanf("%d %d",&n,&m);
for(int i=0,u,v;i<m;i++)
{
scanf("%d %d",&u,&v);
add(u, v);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
Tarjan(i);
}
shrink();
int ans = 0,tmp;
for(int i=1;i<=n;i++)
{
if(!dag[id[i]])
{
if(!ans) tmp = id[i];
else if(tmp!=id[i])
{
ans = 0;
break;
}
ans++;
}
}
printf("%d\n",ans);
}