强连通分量算法·$tarjan$初探
嗯,今天好不容易把鸽了好久的缩点给弄完了……感觉好像……很简单?
算法的目的,其实就是在有向图上,把一个强连通分量缩成一个点……然后我们再对此搞搞事情,\(over\)
哦对,时间复杂度很显然是\(\Theta(n)\)的,懒得\(Proof\)了。
真是简明扼要的算法啊\(233\)
比较弱智的代码是下面的:
#include <stack>
#include <cstdio>
#include <iostream>
#define min Min
#define max Max
#define MAXN 10010
#define MAXM 50010
#define to(k) E[k].to
std::stack <int> S ;
struct Edge{
int to, next ;
}E[MAXM] ; int head[MAXN], vis[MAXN], c ;
int N, M, A, B, Ans, dfn[MAXN], low[MAXN], cnt ;
inline int Min(int a, int b) { return a & ((a - b) >> 31) | b & (~(a - b) >> 31) ; }
inline int Max(int a, int b) { return a & ((b - a) >> 31) | b & (~(b - a) >> 31) ; }
inline void _Add(int u, int v){ E[++ cnt].to = v, E[cnt].next = head[u], head[u] = cnt ;}
void Tarjan(int u){
S.push(u), vis[u] = 1 ;
dfn[u] = low[u] = ++ c ;
for (int k = head[u] ; k ; k = E[k].next){
if (vis[to(k)]) low[u] = min(low[u], low[to(k)]) ;
else if (!dfn[to(k)]) Tarjan(to(k)), low[u] = min(low[u], low[to(k)]) ;
}
if (dfn[u] == low[u]) ++ Ans ;
}
int main(){
int i ; std::cin >> N >> M ;
for (i = 1 ; i <= M ; ++ i) scanf("%d%d", &A, &B), _Add(A, B) ;
for (i = 1 ; i <= N ; ++ i) if (!dfn[i]) Tarjan(i) ; printf("%d", Ans) ; return 0 ;
}
十分\(zz\)的统计联通块个数……当然还有进阶版本:
\(\mathcal{Description}\)
\(\mathcal{Solution}\)
其实就是让求大小非\(1\)的联通块个数……稍微弹个栈就行了\(233\)
#include <stack>
#include <cstdio>
#include <iostream>
#define min Min
#define max Max
#define MAXN 10010
#define MAXM 50010
#define to(k) E[k].to
std::stack <int> S ;
struct Edge{
int to, next ;
}E[MAXM] ; int head[MAXN], vis[MAXN], c ;
int N, M, A, B, Ans, dfn[MAXN], low[MAXN], cnt ;
inline int Min(int a, int b) { return a & ((a - b) >> 31) | b & (~(a - b) >> 31) ; }
inline int Max(int a, int b) { return a & ((b - a) >> 31) | b & (~(b - a) >> 31) ; }
inline void _Add(int u, int v){ E[++ cnt].to = v, E[cnt].next = head[u], head[u] = cnt ;}
void Tarjan(int u){
S.push(u), vis[u] = 1 ;
dfn[u] = low[u] = ++ c ;
for (int k = head[u] ; k ; k = E[k].next){
if (vis[to(k)]) low[u] = min(low[u], low[to(k)]) ;
else if (!dfn[to(k)]) Tarjan(to(k)), low[u] = min(low[u], low[to(k)]) ;
}
if (dfn[u] == low[u]){
int t = 0 ;
while(!S.empty()){
int T = S.top() ;
++ t ; S.pop() ;
if (T == u) break ;
}
Ans += (t > 1) ;
}
}
int main(){
int i ; std::cin >> N >> M ;
for (i = 1 ; i <= M ; ++ i) scanf("%d%d", &A, &B), _Add(A, B) ;
for (i = 1 ; i <= N ; ++ i) if (!dfn[i]) Tarjan(i) ; printf("%d", Ans) ; return 0 ;
}
还有更加进阶的版本:
\(\mathcal{Description}\)
\(\mathcal{Solution}\)
就是缩完点之后跑\(DP\)……\[DP ~ in ~Graph= Floyd = \text{最短路} = SPFA\]这个题里,这个思路好像没问题……
那么就直接缩完点在联通块之间跑\(SPFA\)就行。
#include <stack>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define max Max
#define MAX 100010
#define to(k) E[k].to
using namespace std ;
stack <int> S ;
queue <int> q ;
struct Edge{
int to, next, v ;
}E[MAX] ; int A, B, N, M, Ans, tot, cnt, c ;
int head[MAX], dist[MAX], Edges[MAX][2], val[MAX] ;
int base[MAX], vis[MAX], clr[MAX], dfn[MAX], low[MAX] ;
inline void Tarjan(int now){
S.push(now), vis[now] = 1,
low[now] = dfn[now] = ++ c ;/**/
for (int k = head[now] ; k ; k = E[k].next){
if(vis[to(k)]) low[now] = min(low[now], dfn[to(k)]) ;
else if (!dfn[to(k)]) Tarjan(to(k)), low[now] = min(low[now], low[to(k)]) ;
}
if (dfn[now] == low[now]){
++ tot ;
while(!S.empty()){
int t = S.top() ;
clr[t] = tot, vis[t] = 0,
val[tot] += base[t], S.pop() ;
if (t == now) break ;
}
}
}
inline int Max(int a, int b){ return a & ((b - a) >> 31) | b & (~(b - a) >> 31) ; }
inline void Clear(){cnt = 0, fill(head, head + N + 3, 0) ; memset(E, 0, sizeof(E)) ;}
inline void _Add(int u, int v){ E[++ cnt].to = v, E[cnt].next = head[u], head[u] = cnt ;}
inline void SPFA(int x){
fill(vis, vis + N + 2, 0),
fill(dist, dist + N + 2, 0) ;
dist[x] = val[x], vis[x] = 1, q.push(x) ;
while (!q.empty()){
int now = q.front() ; q.pop(), vis[now] = 0 ;
for (int k = head[now] ; k ; k = E[k].next){
int v = E[k].to ;
if (dist[v] < dist[now] + val[v]) {
dist[v] = dist[now] + val[v] ;
if (!vis[v]) vis[v] = 1, q.push(v) ;
}
}
}
for (int i = 1 ; i <= tot ; ++ i) Ans = max(Ans, dist[i]) ;
}
int main(){
int i ; cin >> N >> M ;
for (i = 1 ; i <= N ; ++ i) scanf("%d", &base[i]) ;
for (i = 1 ; i <= M ; ++ i)
Edges[i][0] = A, Edges[i][1] = B, scanf("%d%d", &A, &B), _Add(A, B) ;
/**/for (i = 1 ; i <= N ; ++ i) if (!dfn[i]) Tarjan(i) ; Clear() ;
for (i = 1 ; i <= M ; ++ i) if (clr[Edges[i][0]] != clr[Edges[i][1]]) _Add(clr[Edges[i][0]], clr[Edges[i][1]]) ;/**/
for (i = 1 ; i <= tot ; ++ i) SPFA(i) ; printf("%d\n", Ans) ; return 0 ;
}
个人觉得缩点……没啥好说的……因为比较简单嘛……
强连通分量算法·$tarjan$初探的更多相关文章
- Tarjan的强连通分量算法
Tarjan算法用于寻找图G(V,E)中的所有强连通分量,其时间复杂度为O(|V|+|E|). 所谓强连通分量就是V的某个极大子集,其中任意两个结点u,v在图中都存在一条从u到v的路径. Tarjan ...
- 有向图的强连通分量的求解算法Tarjan
Tarjan算法 Tarjan算法是基于dfs算法,每一个强连通分量为搜索树中的一颗子树.搜索时,把当前搜索树中的未处理的结点加入一个栈中,回溯时可以判断栈顶到栈中的结点是不是在同一个强连通分量中.当 ...
- 有向图强连通分量的Tarjan算法
有向图强连通分量的Tarjan算法 [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G ...
- 强连通分量的Tarjan算法
资料参考 Tarjan算法寻找有向图的强连通分量 基于强联通的tarjan算法详解 有向图强连通分量的Tarjan算法 处理SCC(强连通分量问题)的Tarjan算法 强连通分量的三种算法分析 Tar ...
- 有向图的强连通分量——Tarjan
在同一个DFS树中分离不同的强连通分量SCC; 考虑一个强连通分量C,设第一个被发现的点是 x,希望在 x 访问完时立刻输出 C,这样就可以实现 在同一个DFS树中分离不同的强连通分量了. 问题就转换 ...
- 有向图强连通分量 Tarjan算法
[有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极 ...
- 图的强连通分量-Kosaraju算法
输入一个有向图,计算每个节点所在强连通分量的编号,输出强连通分量的个数 #include<iostream> #include<cstring> #include<vec ...
- POJ2186 Popular Cows 强连通分量tarjan
做这题主要是为了学习一下tarjan的强连通分量,因为包括桥,双连通分量,强连通分量很多的求法其实都可以源于tarjan的这种方法,通过一个low,pre数组求出来. 题意:给你许多的A->B ...
- 【转】有向图强连通分量的Tarjan算法
原文地址:https://www.byvoid.com/blog/scc-tarjan/ [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly con ...
随机推荐
- Django基础六之ORM中的锁和事务
一 锁 行级锁 select_for_update(nowait=False, skip_locked=False) #注意必须用在事务里面,至于如何开启事务,我们看下面的事务一节. 返回一个锁住行直 ...
- angular2.0---服务Service,使用服务进行数据处理
1.创建服务 打开命令窗口,cd到项目目录下,输入 ng g service myData1 回车 创建服务,如下图所示: 这样就成功创建了服务,此时,可以在项目的app文件夹下生成了两个serv ...
- SystemLogParser ArcGIS Server运维工程师的好助手
单位使用ArcGIS Server发布了众多GIS服务,作为系统运维工程师,一直希望能有一种便捷的方式能获得服务的访问情况,Esri推出的SystemLogParser这款小程序就是不错的辅助工具,而 ...
- Android 图板之保存图像
(1)为了能适应多种屏幕尺寸的手机,我们在创建图像的时候就要根据用户手机屏幕的宽高像素来创建. (2)该软件将把图形保存到sdcard中,在保存之前,需要检测sdcard是否存在,是否可写入.如通过以 ...
- 将远程UI分支克隆到本地UI分支
git checkout -b UI git remote add origin <url> git fetch origin git branch --track UI origin/U ...
- unity3d中的自定义模型的顶点法线和建模软件中的术语“软硬边”和立方体
在unity3d中我是想用Mesh生成一个正方体,直到遇到了法线的问题. 我是想显示如下图所示的正方体,却发现法线设置上的问题. 这里我先使用了8个顶点 按照每个顶点一个法线的结果,只能是这样:(也就 ...
- leetCode题解之根据字符出现的频率排序
1.题目描述 Given a string, sort it in decreasing order based on the frequency of characters. Example 1: ...
- Ajax 请求下载 Execl 文件
通过Ajax请求下载Execl 的问题,掉进一个坑里半个多小时,特此来记录一下 . 起初 我误以为是后台的问题,然而调试了一下并不是这样的,也不会报错,且进入了success 函数. 以下的事件及请 ...
- Linux Transparent Huge Pages 对 Oracle 的影响
1 Transparent Huge Pages 说明 官网上有2篇文章对THP 做了说明: https://access.redhat.com/solutions/46111 https://acc ...
- 转: SSH框架总结(框架分析+环境搭建+实例源码下载)
原:http://blog.csdn.net/shan9liang/article/details/8803989 首先,SSH不是一个框架,而是多个框架(struts+spring+hibernat ...