Popular Cows
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 23843 | Accepted: 9779 |
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
题目大意:给有向图G,求图G中有多少点能从所有起点到达
暴搜必T,故本题需要用Tarjen求有向图的强连通分量。
缩点后得DAG(若有环则属同一强连通分量)
由于无环,故这图为树或树的森林
先判断图是否连通,若为森林则无解
否则,判定每个SSC是否有连出的边(由于图无环,故连出的边上的点无法回去)
答案即为出度为0的连通分量上的点
如果不止一个这样的点,则不同的点无法互相到达
Program P2186;
const
maxn=10000;
maxm=50000;
var
head,edge,tail:array[1..maxm] of longint;
sizeedge:longint;
n,m,i,j,x,y:longint;
ssc,c,dfs,low,outdegree,stack:array[1..maxn] of longint;
time,size:longint;
totssc:longint;
procedure addedge(u,v:longint);
begin
inc(sizeedge);
edge[sizeedge]:=v;
tail[sizeedge]:=head[u];
head[u]:=sizeedge;
end;
function min(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end;
procedure tarjen(k,father:longint);
var
i,j,p:longint;
begin
inc(time);
dfs[k]:=time;low[k]:=time;
c[k]:=1;
inc(size);stack[size]:=k;
p:=head[k];
while (p<>0) do
begin
i:=edge[p];
if (dfs[k]>dfs[i]) then
begin
if c[i]=0 then
begin
tarjen(i,k);
low[k]:=min(low[k],low[i]);
end
else if c[i]=1 then low[k]:=min(low[k],dfs[i]);
end;
p:=tail[p];
end;
if low[k]=dfs[k] then
begin
inc(totssc);
repeat
i:=stack[size];
dec(size);
c[i]:=2;
ssc[i]:=totssc;
until ((size=0) or (i=k));
end;
end;
function main:longint;
var
i,j,tot,node,p:longint;
begin
fillchar(dfs,sizeof(dfs),0);
fillchar(low,sizeof(low),0);
fillchar(c,sizeof(c),0);
fillchar(outdegree,sizeof(outdegree),0);
time:=0;
totssc:=0;
for i:=1 to n do
if (dfs[i]=0) then
begin
fillchar(stack,sizeof(stack),0);
size:=0;
tarjen(i,0);
end;
for i:=1 to n do
begin
p:=head[i];
while (p<>0) do
begin
j:=edge[p];
if (ssc[i]<>ssc[j]) then
begin
inc(outdegree[ssc[i]]);
end;
p:=tail[p];
end;
end;
node:=0;
for i:=1 to totssc do
if outdegree[i]=0 then
begin
if node<>0 then exit(0);
node:=i;
end;
tot:=0;
for i:=1 to n do
if ssc[i]=node then inc(tot);
exit(tot);
end;
begin
sizeedge:=0;
fillchar(head,sizeof(head),0);
fillchar(tail,sizeof(tail),0);
fillchar(edge,sizeof(edge),0);
read(n,m);
for i:=1 to m do
begin
read(x,y);
addedge(x,y);
end;
writeln(main);
end.
现增加ACM,SSC(强连通分量/缩点)Template,撒花 Flower
再说一遍这个算法SSC(强连通分量/缩点):
1.dfs一遍,回溯前给顶点标号
2.把图中的边反向(记为rG),按照标号从小到大rdfs,每次dfs标号k(第k强连通分量)
PS:图中无环(DAG:有向无环图),后标号的点在早标号的点的后面(拓扑序)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
#include<vector>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (10000+10)
#define MAXM (50000+10)
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
typedef long long ll;
class SSC
{
public:
int n,b[MAXN],num[MAXN];
vector<int> G[MAXN],rG[MAXN]; //图,反向后的图
vector<int> vs; //后续遍历顶点列表
void mem(int _n)
{
n=_n; MEM(num)
For(i,n) G[i].clear(),rG[i].clear();
vs.clear();
}
void addedge(int u,int v)
{
G[u].push_back(v);
rG[v].push_back(u);
}
void dfs(int x)
{
b[x]=1;
Rep(i,G[x].size())
{
if (!b[G[x][i]]) dfs(G[x][i]);
}
vs.push_back(x);
}
void rdfs(int x,int k)
{
b[x]=1;num[x]=k;
Rep(i,rG[x].size())
{
if (!b[rG[x][i]]) rdfs(rG[x][i],k);
}
}
int ssc()
{
MEM(b)
For(i,n) if (!b[i]) dfs(i);
MEM(b) int k=0;
RepD(i,vs.size()-1) if (!b[vs[i]]) rdfs(vs[i],++k);
return k;
}
}S;
int n,m;
int main()
{
// freopen("poj2186_template.in","r",stdin);
// freopen(".out","w",stdout);
cin>>n>>m;
S.mem(n);
For(i,m)
{
int u,v;
scanf("%d%d",&u,&v);
S.addedge(u,v);
}
int new_n=S.ssc();
int ans=0,x=0;
For(i,n)
if (S.num[i]==new_n) ans++,x=i;
MEM(S.b)
S.rdfs(x,-1);
For(i,n) if (S.num[i]!=-1) {cout<<"0\n"; return 0;}
cout<<ans<<endl;
return 0;
}