[poj 2553]The Bottom of a Graph[Tarjan强连通分量]
题意:
求出度为0的强连通分量.
思路:
缩点
具体有两种实现:
1.遍历所有边, 边的两端点不在同一强连通分量的话, 将出发点所在强连通分量出度+1.
- #include <cstdio>
- #include <cstring>
- #include <stack>
- #include <algorithm>
- using namespace std;
- //0.03s 4856K
- const 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 4812K
- const 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强连通分量]的更多相关文章
- POJ 2553 The Bottom of a Graph(强连通分量)
POJ 2553 The Bottom of a Graph 题目链接 题意:给定一个有向图,求出度为0的强连通分量 思路:缩点搞就可以 代码: #include <cstdio> #in ...
- poj 2553 The Bottom of a Graph【强连通分量求汇点个数】
The Bottom of a Graph Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 9641 Accepted: ...
- POJ 2553 The Bottom of a Graph(强连通分量的出度)
题意: 求出图中所有汇点 定义:点v是汇点须满足 --- 对图中任意点u,若v可以到达u则必有u到v的路径:若v不可以到达u,则u到v的路径可有可无. 模板:http://www.cnblogs.co ...
- POJ 2553 The Bottom of a Graph (Tarjan)
The Bottom of a Graph Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 11981 Accepted: ...
- POJ 2553 The Bottom of a Graph Tarjan找环缩点(题解解释输入)
Description We will use the following (standard) definitions from graph theory. Let V be a nonempty ...
- POJ 2553 The Bottom of a Graph TarJan算法题解
本题分两步: 1 使用Tarjan算法求全部最大子强连通图.而且标志出来 2 然后遍历这些节点看是否有出射的边,没有的顶点所在的子强连通图的全部点,都是解集. Tarjan算法就是模板算法了. 这里使 ...
- poj 2553 The Bottom of a Graph(强连通、缩点、出入度)
题意:给出一个有向图G,寻找所有的sink点.“sink”的定义为:{v∈V|∀w∈V:(v→w)⇒(w→v)},对于一个点v,所有能到达的所有节点w,都能够回到v,这样的点v称为sink. 分析:由 ...
- poj 2553 The Bottom of a Graph(强连通分量+缩点)
题目地址:http://poj.org/problem?id=2553 The Bottom of a Graph Time Limit: 3000MS Memory Limit: 65536K ...
- POJ 2553 The Bottom of a Graph 【scc tarjan】
图论之强连通复习开始- - 题目大意:给你一个有向图,要你求出这样的点集:从这个点出发能到达的点,一定能回到这个点 思路:强连通分量里的显然都可以互相到达 那就一起考虑,缩点后如果一个点有出边,一定不 ...
随机推荐
- sql 自身连接
"select table1.field1, table2.field1 from table table1, table table2 where table1.id=table2.par ...
- 『奇葩问题集锦』npm install 报错 node-pre-gyp ERR! node-pre-gyp -v v0.6.25
gyp ERR! configure error gyp ERR! stack Error: Can't find Python executable "python", you ...
- lamp环境-编译安装
http://my.oschina.net/JerryBaby/blog/292731 http://blog.chinaunix.net/uid-20639775-id-154442.html ht ...
- 以中断方式实现1s定时
中断方式比较特殊,需要使用单片机内部的中断处理机制,同时指定中断函数. #include <reg52.h> sbit LED = P0^; unsigned ; void main() ...
- 在同一台机器上让Microsoft SQL Server 2000/ SQL2005/ SQL2008共存
可能很多朋友都遇到想同时在自己的机器上运行Microsoft SQL Server 2000以及Microsoft SQL Server 2005和Microsoft SQL Server 2008. ...
- 跨线程操作UI控件
写程序的时候经常会遇到跨线程访问控件的问题,看到不少人去设置Control.CheckForIllegalCrossThreadCalls = false;这句话是告诉编译器不要对跨线程访问作检查,可 ...
- xcode 自动添加注释,生成文档
一.自动生成注释代码 添加一个快捷键,生成 注释代码 ThisService 下载连接:http://wafflesoftware.net/thisservice/ ...
- XE5 开发android平台搭建
转载自:http://www.cnblogs.com/hezihang/p/3319980.html Delphi XE5的Android开发平台搭建 Delphi XE5支持Android AR ...
- [JavaScript] js实现简单的代码运行框
<script type="text/javascript">// <![CDATA[ function runCode(obj) { var winname = ...
- python中的字典(dict),列表(list),元组(tuple)
一,List:列表 python内置的一种数据类型是列表:list.list是一种有序的数据集合,可以随意的添加和删除其中的数据.比如列出班里所有的同学的名字,列出所有工厂员工的工号等都是可以用到列表 ...