POJ 2186(有向图的强连通分量)[改][Template:SSC/缩点]

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. 

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. 

Source

USACO 2003 Fall




题目大意:给有向图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;
}








你可能感兴趣的:(c)