[poj 2553]The Bottom of a Graph[Tarjan强连通分量]
来源:互联网 发布:mac 如何打破折号 编辑:程序博客网 时间:2024/06/07 12:20
题意:
求出度为0的强连通分量.
思路:
缩点
具体有两种实现:
1.遍历所有边, 边的两端点不在同一强连通分量的话, 将出发点所在强连通分量出度+1.
#include <cstdio>#include <cstring>#include <stack>#include <algorithm>using namespace std;//0.03s 4856Kconst int MAXN = 5005;struct Pool{ int pre, v;}p[MAXN*100];//适当开int num,head[MAXN];int low[MAXN];int dfn[MAXN],Index;int id[MAXN],size;bool vis[MAXN];stack<int> s;int n,m;int deg[MAXN];void clear(){ num = 1;//求邻边,异或方便,从2开始 memset(head,0,sizeof(head)); memset(vis,false,sizeof(vis)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(deg,0,sizeof(deg)); Index = size = 0; while(!s.empty()) s.pop();}void add(int u, int v){ p[++num].v = v; p[num].pre = head[u];//pre为0,说明该边为第一条边 head[u] = num;}void Tarjan(int u){ dfn[u] = low[u] = ++Index; s.push(u); vis[u] = true; for(int tmp = head[u],k;k = p[tmp].v,tmp; tmp = p[tmp].pre) { if(!dfn[k]) { Tarjan(k); low[u] = min(low[u], low[k]); } else if(vis[k]) { low[u] = min(low[u], low[k]); ///low[u] = min(low[u], dfn[k]);这两种都可以啦~ } } if(dfn[u]==low[u]) { size++; int k; do { k = s.top(); s.pop(); vis[k] = false; id[k] = size; }while(k!=u); }}void cal(){ for(int i=1;i<=n;i++) { for(int tmp = head[i],k;k = p[tmp].v,tmp; tmp = p[tmp].pre) { if(id[i]!=id[k]) { deg[id[i]]++; } } }}int main(){ while(scanf("%d",&n),n) { clear(); scanf("%d",&m); for(int i=0,u,v;i<m;i++) { scanf("%d %d",&u,&v); add(u,v); } for(int i=1;i<=n;i++) { if(!dfn[i]) Tarjan(i); } cal(); bool blank = false; for(int i=1;i<=n;i++) { if(!deg[id[i]]) { if(!blank) { printf("%d",i); blank = true; } else printf(" %d",i); } } printf("\n"); }}
2. 在dfs的过程中,标记出度.
设当前节点为u
若访问到了黑色点, 则出度不为0.
若访问到了灰色点, 正常
若访问到了白色点, 则这个白色点k
若被搜索之后属于同一强连通分量,则low[ k ] < dfn[ k ] (注意,并不一定有 low[ k ] < low[ u ], 因为k可能连接到了较靠后的灰色点,而u之前已经被较靠前的灰色点更新过).
若被搜索之后属于另一个(不同于u的)强连通分量, 那么可以证明 low[ k ] == dfn[ k ], 即k一定是入口.
黑体字的两条就包括了所有出度非0的情况. 据此来实现缩点.
#include <cstdio>#include <cstring>#include <stack>#include <algorithm>using namespace std;//0.03s 4812Kconst int MAXN = 5005;struct Pool{ int pre, v;}p[MAXN*100];//适当开int num,head[MAXN];int low[MAXN];int dfn[MAXN],Index;int id[MAXN],size;bool vis[MAXN];stack<int> s;int n,m;bool black[MAXN];bool odd[MAXN];void clear(){ num = 1; memset(head,0,sizeof(head)); memset(vis,false,sizeof(vis)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(black,false,sizeof(black)); memset(odd,false,sizeof(odd)); Index = size = 0; while(!s.empty()) s.pop();}void add(int u, int v){ p[++num].v = v; p[num].pre = head[u]; head[u] = num;}void Tarjan(int u){ dfn[u] = low[u] = ++Index; s.push(u); vis[u] = true; for(int tmp = head[u],k;k = p[tmp].v,tmp; tmp = p[tmp].pre) { if(!dfn[k]) { Tarjan(k); if(low[k]==dfn[k])///如果访问到了白色点,那么新的强连通分量的入口一定在这个点 black[u] = true; low[u] = min(low[u], low[k]); } else if(vis[k]) { low[u] = min(low[u], low[k]); } else black[u] = true; }///low只是指"当前找到的强连通分量的进入时间戳" ///而非"极大强连通分量"的进入时间戳.但是肯定小于自己的时间戳(恰好是进入点的话就是等于). if(dfn[u]==low[u]) { size++; int k; do { k = s.top(); s.pop(); vis[k] = false; id[k] = size; if(black[k]) odd[size] = true; }while(k!=u); }}int main(){ while(scanf("%d",&n),n) { clear(); scanf("%d",&m); for(int i=0,u,v;i<m;i++) { scanf("%d %d",&u,&v); add(u,v); } for(int i=1;i<=n;i++) { if(!dfn[i]) Tarjan(i); } bool blank = false; for(int i=1;i<=n;i++) { if(!odd[id[i]]) { if(!blank) { printf("%d",i); blank = true; } else printf(" %d",i); } } printf("\n"); }}
- POJ 2553 The Bottom of a Graph 强连通分量+缩点 tarjan or kosaraju
- [poj 2553]The Bottom of a Graph[Tarjan强连通分量]
- POJ 2553 The Bottom of a Graph(Tarjan,强连通分量)
- POJ-2553 The Bottom of a Graph (强连通分量[Tarjan])
- 强连通分量 ( Tarjan,邻接链表 )——The Bottom of a Graph ( POJ 2553 )
- POJ 2553 The Bottom of a Graph(Tarjan Algorithm强连通分量)
- poj 2553 The Bottom of a Graph(强连通分量)
- POJ 2553 The Bottom of a Graph 强连通分量
- POJ 2553 The Bottom of a Graph(强连通分量)
- POJ 2553 The Bottom of a Graph (强连通分量)
- POJ 2553 The Bottom of a Graph(强连通分量)
- POJ 2553 The Bottom of a Graph 强连通分量
- poj 2553 The Bottom of a Graph【强连通分量】
- Poj 2533 The Bottom of a Graph【强连通Tarjan】
- poj 2553 zoj 1979 The Bottom of a Graph(强联通分量 Tarjan)
- POJ 2553 The Bottom of a Graph(强连通分量)
- POJ 2553The Bottom of a Graph 强连通分量分解
- POJ 2553——The Bottom of a Graph(强连通分量)
- License Exception
- 如何训练幼儿的手指
- Android系统Recovery工作原理之使用update.zip升级过程分析(三)
- Java - 类加载器 和 JVM
- IOS开发学习笔记(二十)——Core Data使用(中篇)
- [poj 2553]The Bottom of a Graph[Tarjan强连通分量]
- jquery中$(function(){...})的含义
- 在 Windows 上安装和使用 GNUstep 和 Objective-C
- 【分享】PK10彩票历史数据
- Nginx Rewrite重写
- Android系统Recovery工作原理之使用update.zip升级过程分析(四)
- hdu4441 Queue Sequence(线段树+splay)
- Minix中的字符判定ctype.c
- Extjs中隐藏某个textfield以及label组件的方法