题目链接: poj 2186
题目大意: 给定有向图,满足X使得图中任意的顶点Y都存在Y-->X的路径
计算X满足条件的顶点总数
解题思路: Kosataju找联通分量,缩成点
出度为0的顶点必须有且仅有一个
如果出度为0的顶点有若干个,那么这些联通分量之间是不可到达的
出度为0的联通分量中的点都满足题意
代码:
//Final Kosaraju+缩点
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 110000
struct snode{
int to,next;
}edge1[MAX*50],edge2[MAX*50];
int n,Index1,Index2,visit[MAX],pre1[MAX],pre2[MAX],num[MAX];
int k,list[MAX],father[MAX],In[MAX],To[MAX];
void Add_edge(int a,int b) //建立正向反向图
{
edge1[Index1].to=b,edge1[Index1].next=pre1[a];
pre1[a]=Index1++;
edge2[Index2].to=a,edge2[Index2].next=pre2[b];
pre2[b]=Index2++;
}
void Kosaraju(int u) //Kosaraju搜索强联通分量
{
int i,v;
visit[u]=1;
for(i=pre1[u];i!=-1;i=edge1[i].next)
{
v=edge1[i].to;
if(!visit[v])
Kosaraju(v);
}
list[k++]=u;
}
void DFS(int u,int Father) //
{
int i,v;
visit[u]=2;
father[u]=Father;
for(i=pre2[u];i!=-1;i=edge2[i].next)
{
v=edge2[i].to;
if(visit[v]==1)
DFS(v,Father);
}
}
void Add_edge2(int a,int b) //建立缩点之后的图
{
int i;
if(a==b)
return ;
for(i=pre2[a];i!=-1;i=edge2[i].next)
{
if(edge2[i].to==b) //去除重复的边
return ;
}
In[b]++; To[a]++;
edge2[Index2].to=b,edge2[Index2].next=pre2[a];
pre2[a]=Index2++;
}
int main()
{
int m,i,j,a,b,c,k1,k2,k3;
while(scanf("%d%d",&n,&m)!=EOF)
{
Index1=Index2=0;
memset(In,0,sizeof(In));
memset(To,0,sizeof(To));
memset(num,0,sizeof(num));
memset(pre1,-1,sizeof(pre1));
memset(pre2,-1,sizeof(pre2));
memset(visit,0,sizeof(visit));
memset(father,0,sizeof(father));
for(i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
Add_edge(a,b);
}
if(m<n-1) //如果不能构成图或者树
{
printf("0\n");
continue;
}
for(i=1,k=0;i<=n;i++)
{
if(!visit[i])
{
Kosaraju(i);
}
}
for(j=k-1,c=0;j>=0;j--) //按照Kosaraju搜索点的顺序分块搜索
{
if(visit[list[j]]==1)
DFS(list[j],++c);
}
Index2=0; //初始化
memset(pre2,-1,sizeof(pre2));
for(i=1;i<=n;i++) //为正向图建立缩点之后的图
{
for(j=pre1[i];j!=-1;j=edge1[j].next)
{
Add_edge2(father[i],father[edge1[j].to]);
}
}
if(c==1) //为联通图则输出n
{
printf("%d\n",n);
continue;
}
for(i=1;i<=n;i++)
num[father[i]]++;
for(i=1,a=-1,k1=k2=k3=0;i<=c;i++)
{
if(To[i]==0) //终点
{
k2++;
a=i;
}
}
if(k2==1) //***只有一个终点
printf("%d\n",num[a]);
else
printf("0\n");
}
return 0;
}