//学习啊……原来id【i】==1的就是出度为0的。
以前没有把强连通tarjan搞懂,上午看了下,终于理解过程了,递归之经典。
然后去做2186, 其实开始的时候对缩点后的算法不是很清楚,关键在于:最后的答案就等于唯一一个出度为0的强连通分支内的顶点数,关键在于这个唯一!当不止一个强连通分支的出度为0的时候,因为其中任意2个强连通分支之间没连通,所以不可能存在一个牛被其他所有牛崇拜。
于是,最后一步在于找有几个强连通分支的出度为0,这个很好办的,把图再扫一遍就是了。
#include <cstdlib>
#include <iostream>
using namespace std;
#define Max 10010
typedef struct node{
int to;
node *next;
};
int stack[Max]; //DFS存节点的栈
int low[Max],ord[Max], id[Max],n,m,cnt,scnt,n2,map[Max];
//low是tarjan算法中定义的, ord是存点在dfs中出现的次序,id存点属于第几个连通分支, map存强连通分量缩点后出度是否为0, cnt,dfs过程序号,scnt强连通分支数目。
low数组是tarjan算法的关键,不大好理解,不过用例子模拟下就可以理解了,可以形象的理解为low[u]表示,从u点能回到的最早被遍历的点的dfs序号。
bool instack[Max]; //点是否在栈中
node *g[Max];//邻接表
void insert(int u,int v)//邻接表插入函数
{
node *tmp = new node;
tmp -> to = v;
tmp -> next = g[u];
g[u] = tmp;
}
void Tarjan(int e)// tarjan算法的dfs过程,不断更新low,和ord数组
{
int i,t,k;
low[e] = ++cnt;
ord[e] = cnt;
stack[++stack[0]] = e;
instack[e] = true;
node *tmp = g[e];
while(tmp != NULL)
{
t = tmp -> to;
if(!ord[t])
{
Tarjan(t);
if(low[t] < low[e]) low[e] = low[t];
}
else if(instack[t] && low[e] > ord[t])//如果已经在栈中
low[e] = ord[t];
tmp = tmp -> next;
}
if(low[e] == ord[e])//找到强连通分支的根
{
scnt ++;
do{// 找到这个强连通分支内的点
t = stack[stack[0]--];
id[t] = scnt;
instack[t] = false;
}while(t != e);
}
return;
}
void find_components(int n)//tarjan算法主过程:依次dfs没有访问过的点
{
int i;
memset(ord,0,sizeof(ord));
memset(instack,false,sizeof(instack));
cnt = 0;
scnt = 0;
stack[0] = 0;
for(i=1;i<=n;i++)
if(!ord[i])
Tarjan(i);
}
int main(int argc, char *argv[])
{
while(scanf("%d%d",&n,&m) == 2)
{
int i,j,k,l,e;
memset(g,NULL,sizeof(g));
for(i=1;i<=m;i++)//建图
{
scanf("%d%d",&k,&l);
insert(k,l);
}
cnt = 0;
find_components(n);
n2 = scnt;
memset(map, 0 , sizeof (map));
int ans = 0;
for(i=1;i<=n;i++)//判断每个连通分支的出度是否为0
{
if(id[i] == 1) ans++;
node *tmp;
tmp = g[i];
while(tmp!=NULL)
{
e = tmp->to;
if(id[i] != id[e] && !map[id[i]])
map[id[i]] = 1;
tmp = tmp->next;
}
}
int flag = 0;
for(i=1;i<=n2;i++)//找连通分支出度为0的点的个数
if(!map[i]) flag ++;
if(flag > 1) printf("%d/n",0);
else printf("%d/n",ans);
}
return EXIT_SUCCESS;
}