题意:

求出度为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强连通分量]的更多相关文章

  1. POJ 2553 The Bottom of a Graph(强连通分量)

    POJ 2553 The Bottom of a Graph 题目链接 题意:给定一个有向图,求出度为0的强连通分量 思路:缩点搞就可以 代码: #include <cstdio> #in ...

  2. poj 2553 The Bottom of a Graph【强连通分量求汇点个数】

    The Bottom of a Graph Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 9641   Accepted:  ...

  3. POJ 2553 The Bottom of a Graph(强连通分量的出度)

    题意: 求出图中所有汇点 定义:点v是汇点须满足 --- 对图中任意点u,若v可以到达u则必有u到v的路径:若v不可以到达u,则u到v的路径可有可无. 模板:http://www.cnblogs.co ...

  4. POJ 2553 The Bottom of a Graph (Tarjan)

    The Bottom of a Graph Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 11981   Accepted: ...

  5. POJ 2553 The Bottom of a Graph Tarjan找环缩点(题解解释输入)

    Description We will use the following (standard) definitions from graph theory. Let V be a nonempty ...

  6. POJ 2553 The Bottom of a Graph TarJan算法题解

    本题分两步: 1 使用Tarjan算法求全部最大子强连通图.而且标志出来 2 然后遍历这些节点看是否有出射的边,没有的顶点所在的子强连通图的全部点,都是解集. Tarjan算法就是模板算法了. 这里使 ...

  7. poj 2553 The Bottom of a Graph(强连通、缩点、出入度)

    题意:给出一个有向图G,寻找所有的sink点.“sink”的定义为:{v∈V|∀w∈V:(v→w)⇒(w→v)},对于一个点v,所有能到达的所有节点w,都能够回到v,这样的点v称为sink. 分析:由 ...

  8. poj 2553 The Bottom of a Graph(强连通分量+缩点)

    题目地址:http://poj.org/problem?id=2553 The Bottom of a Graph Time Limit: 3000MS   Memory Limit: 65536K ...

  9. POJ 2553 The Bottom of a Graph 【scc tarjan】

    图论之强连通复习开始- - 题目大意:给你一个有向图,要你求出这样的点集:从这个点出发能到达的点,一定能回到这个点 思路:强连通分量里的显然都可以互相到达 那就一起考虑,缩点后如果一个点有出边,一定不 ...

随机推荐

  1. 以前写过的ajax基础案例(王欢-huanhuan)

    //load方法的使用   $('#loadBtn').click(function(){    //responseTxt 包含来自请求的结果数据 //statusTxt 包含请求的状态(" ...

  2. 【转】PFILE和SPFILE介绍

    原文:http://blog.sina.com.cn/s/blog_77bba23901017xcl.html 一.PFILE Pfile(Parameter File,参数文件)是基于文本格式的参数 ...

  3. simplexml 使用实例

    搞了几天php处理xml文件,终于有点头绪,记录下来分享一下.simplexml 是php处理xml文件的一个方法,另一个是dom处理,这里只说simplexml.目前php处理xml用的比较多,比较 ...

  4. letcode刷题之两数相加

    letcode里面刷题,坑还是链表不熟,(1)头结点还是有必要设置,否则返回的时候找不到位置:(2)先设置next到新节点再next到下一个节点:都是基础知识 /* * * You are given ...

  5. Django下TemplateDoesNotExist 异常的解决方法:

    在settings中添加代码如下获取templates路径: import os import os.path BASE_DIR = os.path.dirname(os.path.dirname(_ ...

  6. comet ajax轮询

    http://www.ibm.com/developerworks/cn/webservices/ws-tip-jaxwsrpc.html http://www.cnblogs.com/pifoo/a ...

  7. Z-Stack 软件架构分析

    转自Z-Stack 软件架构分析 Z-Stack的main函数在Zmain.c中,总体上来说,它一共做了两件工作,一个是系统初始化,即有启动代码来初始化硬件系统和软件架构需要的各个模块,另一个作用就是 ...

  8. JAVA与编译语言及解释语言的关系

    转自JAVA结合了编译和解释执行的优点 编译型语言是一次性编译成机器码,脱离开发环境独立运行,所以运行效率较高,但是由于编译成的是特定平台上机器码,所以可移植性差. 编译型语言的典型代表有C.C++. ...

  9. win7+ubuntu双系统安装攻略

    一1.下载分区软件,为ubuntu安装分出一个区 2.磁盘管理器,选中该区,右键,删除卷,该区变为绿色,成为空闲区 3.成功 二为ubunt添加开机导引项 1,安装好easybcd2.0后,启动软件: ...

  10. 使用API网关构建微服务

    使用传统的异步回调方法编写API组合代码会让你迅速坠入回调地狱.代码会变得混乱.难以理解且容易出错.一个更好的方法是使用响应式方法以一种声明式样式编写API网关代码.响应式抽象概念的例子有Scala中 ...