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

POJ2186 Popular Cows 【裸缩环+Gabow算法强连通分量分解再建图】

2014-06-03 16:06 363 查看
这题比较裸,根据牛的膜拜情况建图,然后强连通分量处理,处理后再建新图,记录出度入度,找出所有出度为0的,如果有2个及以上的,则输出(0),很简单,不可能有被所有牛膜拜的牛了(因为这几个结点互相不可达)。如果只有一个,看这个缩环里面有几个原来的结点,就是答案。

用vector还是有点慢,得好好熟悉一下两个数组维护的那个邻接表,一个数组存每个结点的边链表的末尾边的序号,每条边是一个结构体,下标就是边序号,里面3个变量,一个存到的结点,一个存这条边的前驱(因为是边链表嘛),一个存权值(没有必要存from了,因为我们通过last[i]知道这条链是哪个结点发出的边)

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <cmath>
using namespace std;
const int MAX_V=11111;
vector<int> adj[MAX_V];
vector<int> Gafter[MAX_V];
int in[MAX_V],out[MAX_V];
int n,m;
int intm[MAX_V],belg[MAX_V],stk1[MAX_V],stk2[MAX_V];

void Visit(int cur, int &sig, int &scc_num){//cur带表当前点的序号
int i;
intm[cur] = ++sig;//记录当前点的遍历时刻
stk1[++stk1[0]] = cur;//0存着游标,把当前点的标号压进栈1,2
stk2[++stk2[0]] = cur;
for ( i=0; i<adj[cur].size(); ++i )//扫描当前点的所有边
{
if ( 0==intm[adj[cur][i]] )//没扫过的,则对该点深搜
{
Visit(adj[cur][i],sig,scc_num);
}
else if ( 0==belg[adj[cur][i]] )//扫描过的,如果栈顶元素的时间晚于当前点扫描的当前边连接的点的时间,则弹出栈顶元素
{
while ( intm[stk2[stk2[0]]]>intm[adj[cur][i]] )
{
-- stk2[0];
}
}
}
if ( stk2[stk2[0]]==cur )//如果栈顶元素等于当前元素,则弹出栈顶元素,增加强连通分量的数量,维护环
{
-- stk2[0]; ++ scc_num;
do
{
belg[stk1[stk1[0]]] = scc_num;
}
while ( stk1[stk1[0]--]!=cur );//stk1中当前点之前的点都是属于这个强连通分量的
}
}
//Gabow算法,求解belg[1..n],且返回强连通分量个数,
int Gabow_StronglyConnectedComponent(){
int i, sig, scc_num;//sig访问时间,scc_num第几个强连通分量
memset(belg+1,0,sizeof(int)*n);
memset(intm+1,0,sizeof(int)*n);
sig = 0; scc_num = 0; stk1[0] = 0; stk2[0] = 0;
for ( i=1; i<=n; ++i )
{
if ( 0==intm[i] )//该点没访问过
{
Visit(i,sig,scc_num);
}
}
return scc_num;
}

int main()
{
#ifndef ONLINE_JUDGE
freopen("G:/1.txt","r",stdin);
freopen("G:/2.txt","w",stdout);
#endif
scanf("%d%d",&n,&m);
int x,y;
for(int i=1;i<=m;i++)//输入边
{
scanf("%d%d",&x,&y);
adj[x].push_back(y);
}
int after_num=Gabow_StronglyConnectedComponent();//强连通量分解,分解结果保存在belt里面
int tmp1,tmp2;
for(int i=1;i<=n;i++)//建立新图
{
for(int j=0;j<adj[i].size();j++)
{
tmp1=belg[i],tmp2=adj[i][j];
if(tmp1!=belg[tmp2])
{
Gafter[tmp1].push_back(belg[tmp2]);
in[belg[tmp2]]++;out[tmp1]++;
}
}
}
int outiszero_num=0;
int scc_index=0;
for(int i=1;i<=after_num;i++)//get那个出度为0的新结点(缩环)
{
if(out[i]==0)
{
outiszero_num++;
if(outiszero_num>=2)
{
printf("0\n");
return 0;
}
scc_index=i;
}
}
int ans=0;
for(int i=1;i<=n;i++)//统计有多少个结点在这个缩环中
{
if(belg[i]==scc_index)
ans++;
}
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: