POJ2186 Popular Cows 【裸缩环+Gabow算法强连通分量分解再建图】
2014-06-03 16:06
363 查看
这题比较裸,根据牛的膜拜情况建图,然后强连通分量处理,处理后再建新图,记录出度入度,找出所有出度为0的,如果有2个及以上的,则输出(0),很简单,不可能有被所有牛膜拜的牛了(因为这几个结点互相不可达)。如果只有一个,看这个缩环里面有几个原来的结点,就是答案。
用vector还是有点慢,得好好熟悉一下两个数组维护的那个邻接表,一个数组存每个结点的边链表的末尾边的序号,每条边是一个结构体,下标就是边序号,里面3个变量,一个存到的结点,一个存这条边的前驱(因为是边链表嘛),一个存权值(没有必要存from了,因为我们通过last[i]知道这条链是哪个结点发出的边)
用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; }
相关文章推荐
- POJ2186 Popular Cows
- POJ2186:Popular Cows(tarjan+缩点)
- POJ2186 Popular Cows(强连通分量)
- POJ2186 Popular Cows [强连通分量|缩点]
- POJ 2186 Popular Cows(强连通分量分解)
- poj2186 Popular Cows(tarjan + 缩点)
- [强连通分量]poj2186_Popular Cows
- poj2186 Popular Cows--Kosaraju算法 & 缩点 & 强连通分量
- POJ2186 Popular Cows
- POJ2186 Popular Cows 【强连通分量】+【Kosaraju】+【Tarjan】
- poj2186 Popular Cows(强连通分量)
- [POJ2186]Popular Cows
- POJ2186 Popular Cows 【强连通分量】+【Kosaraju】+【Tarjan】+【Garbow】
- poj2186 Popular Cows (Tarjan )
- Poj2186 Popular Cows
- POJ2186 Popular Cows 强连通分量
- poj2186 Popular Cows
- Poj2186 Popular Cows
- POJ2186(强连通分量分解)
- 有向图的强连通分量的分解 总结 poj2186例题举例