您的位置:首页 > 运维架构

POJ_2186 Popular Cows

2010-10-26 19:18 316 查看
http://poj.org/problem?id=2186

#include <cstdlib>
#include <iostream>

using namespace std;

#define Max 10010

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 t;
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;//id[t]表示节点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()
{
//   freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m) == 2)
{
int i,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 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: