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

来源:互联网 发布:淘宝订单物流查询 编辑:程序博客网 时间:2024/06/05 10:00

 这题比较裸,根据牛的膜拜情况建图,然后强连通分量处理,处理后再建新图,记录出度入度,找出所有出度为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_JUDGEfreopen("G:/1.txt","r",stdin);freopen("G:/2.txt","w",stdout);#endifscanf("%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;}


 

0 0