//学习啊……原来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;
}
2351

被折叠的 条评论
为什么被折叠?



