近期一直在刷这方面的题 因为没法学新知识 但又想写点什么 就水篇博文吧

引理

简单来说,在一个有向图中,若所有点之间两两互相直接可达,则将这个图成为强连通分量

强连通分量可以是某个有向图中的子图

求强连通分量可以使用 Tarjan,Kosaraju 或者 Garbow 算法

个人感觉 Tarjan算法 最实用,而且后两种算法并不是很熟练,因此在这里只讲 Tarjan算法

Tarjan算法

发明者 Robert E.Tarjan 罗伯特·塔扬,美国计算机科学家

塔老爷子发明过很多算法,而且大多是以他的名字命名的,所以 Tarjan算法 也分很多种,这里只说如何求强连通分量

首先需要知道什么是 DFS序

一个结点 \(x\) 的 DFS序 是指深度优先搜索遍历时改结点被搜索的次序,简记为 \(dfn[x]\)

然后,再维护另一个变量 \(low[x]\)

\(low[x]\) 表示以下节点的 DFS序 的最小值:以 \(x\) 为根的子树中的结点 和 从该子树通过一条不在搜索树上的边能到达的结点

根据 DFS 的遍历原理可以发现

  • 一个结点的子树内结点的 DFS序 都大于该结点的 DFS序

  • 从根开始的一条路径上的 DFS序 严格递增,low值 严格非降

知道了这些,再来看 Tarjan算法 求强连通分量的具体内容

我们一般只对还没有确定其 DFS序 的节点进行 Tarjan 操作,操作主要包括两个部分

第一部分

以 DFS 的形式,处理出当前点 \(x\) 的 \(dfn[x]\) 和 \(low[x]\)

对当前点打一个标记表示已经遍历过,在之后的 DFS 中根据是否遍历过来进行不同处理,具体方式如下:

设当前枚举点为 \(fr\),\(fr\) 连出去的点记为 \(to\)

  1. \(to\) 未被访问:继续对 \(to\) 进行深度搜索。在回溯过程中,用 \(low[to]\) 更新 \(low[fr]\)。因为存在从 \(fr\) 到 \(to\) 的直接路径,所以 \(to\) 能够回溯到的已经在栈中的结点, \(fr\) 也一定能够回溯到。
  2. \(to\) 被访问过,已经在栈中:即已经被访问过,根据 low值 的定义(能够回溯到的最早的已经在栈中的结点),则用 \(dfn[to]\) 更新 \(low[fr]\) 。
  3. \(to\) 被访问过,已不在在栈中:说明 \(to\) 已搜索完毕,其所在连通分量已被处理,所以不用对其做操作。

这一部分代码实现如下:

low[fr]=dfn[fr]=++cnt;vis[fr]=1;
for(int i=head[fr];i;i=e[i].nxt){
int to=e[i].to;
if(!dfn[to]) tarjan(to),low[fr]=min(low[fr],low[to]);
else if(vis[to]) low[fr]=min(low[fr],dfn[to]);
}

第二部分

对于一个连通分量图,我们很容易想到,在该连通图中有且仅有一个 \(dfn[x]=low[x]\)

该结点一定是在深度遍历的过程中,该连通分量中第一个被访问过的结点,因为它的 DFS序 和 low值 最小,不会被该连通分量中的其他结点所影响

我们可以维护一个栈,存储所有枚举到的点

因此,在回溯的过程中,判定 \(dfn[x]=low[x]\) 的条件是否成立,如果成立,则从栈中取出一个点,处理它所在的强连通分量的编号以及大小,也可以处理其他的一些操作,这样直到把所有点处理完为止

这一部分的代码实现如下:

zhan[++top]=u;
if(dfn[u]==low[u]){
++siz[++t];
int pre=zhan[top--];
vis[pre]=0;num[pre]=t;
while(pre!=u){
++siz[t];pre=zhan[top--];
vis[pre]=0;num[pre]=t;
}
}

至此,便可以处理出一个点所在的强连通分量,时间复杂度为 \(O(n+m)\)

2-SAT

SAT 是适定性(Satisfiability)问题的简称。一般形式为 k-适定性问题,简称 k-SAT。而当 \(k>2\) 时该问题为 NP 完全的。所以我们只研究 \(k=2\) 的情况。 —— OI Wiki

个人感觉,就是一个实际应用类的知识吧

就是指定 \(n\) 个集合,每个集合包含两个元素,给出若干个限制条件,每个条件规定不同集合中的某两个元素不能同时出现,最后问在这些条件下能否选出 \(n\) 个不在同一集合中的元素

这个问题一般用 Tarjan算法 来求解,也可以使用爆搜,可以参考OI Wiki上的说明,这里就只讲用 Tarjan 实现

但这种问题的实现主要不是难在 Tarjan 怎么写,而是难在图怎么建

假设这里有两个集合 \(A=\{x_1,y_1\}\),\(B=\{x_2,y_2\}\),规定 \(x_1\) 与 \(y_2\) 不可同时出现,那我们就建两条有向边 \((x_1,y_1)\),\((y_2,x_2)\),表示选了 \(x_1\) 必须选 \(y_1\),,选了 \(y_2\) 必须选 \(x_2\)

这样建完边之后只需要跑一边 Tarjan 判断有无解,若有解就把几个不矛盾的强连通分量拼起来就好了

这里注意,因为跑 Tarjan 用了栈,根据拓扑序的定义和栈的原理,可以得到 跑出来的强连通分量编号是反拓扑序 这一结论

我们就可以利用这一结论,在输出方案时倒序得到拓扑序,然后确定变量取值即可

时间复杂度同上为 \(O(n+m)\)

例题

[APIO2009]抢掠计划

[USACO5.3]校园网Network of Schools

[ZJOI2007]最大半连通子图

[POI2001]和平委员会

写在后面

这种知识加起来已经学过好几遍了,但是写起来还是很累,总是怕自己说不明白

有一说一,我是真不理解有人只放个题目链接然后放个代码是怎么想的,连思路都不提,是给别人写 std 还是只为了告诉别人自己做对了

比我还水

强连通分量 与 2-SAT的更多相关文章

  1. 强连通分量SCC 2-SAT

    强连通分量SCC 2-SAT 部分资料来自: 1.https://blog.csdn.net/whereisherofrom/article/details/79417926 2.https://ba ...

  2. HDU5934 强连通分量

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5934 根据距离关系建边 对于强连通分量来说,只需引爆话费最小的炸弹即可引爆整个强连通分量 将所有的强连通分 ...

  3. POJ1236Network of Schools[强连通分量|缩点]

    Network of Schools Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 16571   Accepted: 65 ...

  4. 有向图的强连通分量的求解算法Tarjan

    Tarjan算法 Tarjan算法是基于dfs算法,每一个强连通分量为搜索树中的一颗子树.搜索时,把当前搜索树中的未处理的结点加入一个栈中,回溯时可以判断栈顶到栈中的结点是不是在同一个强连通分量中.当 ...

  5. Tarjan算法--强连通分量

    tarjan的过程就是dfs过程. 图一般能画成树,树的边有三种类型,树枝边 + 横叉边(两点没有父子关系) + 后向边(两点之间有父子关系): 可以看到只有后向边能构成环,即只有第三张图是强连通分量 ...

  6. 强连通分量的一二三 | | JZOJ【P1232】 | | 我也不知道我写的什么

    贴题: 在幻想乡,上白泽慧音是以知识渊博闻名的老师.春雪异变导致人间之里的很多道路都被大雪堵塞,使有的学生不能顺利地到达慧音所在的村庄.因此慧音决定换一个能够聚集最多人数的村庄作为新的教学地点.人间之 ...

  7. 有向图强连通分量的Tarjan算法

    有向图强连通分量的Tarjan算法 [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G ...

  8. poj2186Popular Cows(Kosaraju算法--有向图的强连通分量的分解)

    /* 题目大意:有N个cows, M个关系 a->b 表示 a认为b popular:如果还有b->c, 那么就会有a->c 问最终有多少个cows被其他所有cows认为是popul ...

  9. Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)【转】【修改】

    一.基本概念: 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成 ...

随机推荐

  1. think in java interview-高级开发人员面试宝典(一)

    "生死六重门" 无论你是在职,非在职,高级工程师,工程师,架构师,如果你正在面试阶段,请看完此文! 相信这篇文章对你的职业生涯和阶值观会造成重大的改变! 如果你是一名PM或者是管理 ...

  2. 【目标检测】基于传统算法的目标检测方法总结概述 Viola-Jones | HOG+SVM | DPM | NMS

    "目标检测"是当前计算机视觉和机器学习领域的研究热点.从Viola-Jones Detector.DPM等冷兵器时代的智慧到当今RCNN.YOLO等深度学习土壤孕育下的GPU暴力美 ...

  3. Spring boot JPA读取数据库方法

    方法1: 1 StringBuffer sb = new StringBuffer(300); 2 sb.append("SELECT v.id, v.container_number, v ...

  4. 解析SwiftUI布局细节(三)地图的基本操作

    前言 前面的几篇文章总结了怎样用 SwiftUI 搭建基本框架时候的一些注意点(和这篇文章在相同的分类里面,有需要了可以点进去看看),这篇文章要总结的东西是用地图数据处理结合来说的,通过这篇文章我们能 ...

  5. 九、kafka伪分布式和集群搭建

    伪分布式: 1.先将zk启动,如果是在伪分布式下,kafka已经集成了zk nohup /kafka_2.11-0.10.0.1/bin/zookeeper-server-start.sh /kafk ...

  6. wdcp的一个安全漏洞 2015 9 月

    wdcp的一个安全漏洞,非常严重,请大家及时升级和检查 在九月份的时候,wdcp出了一个很严重的安全漏洞,当时也出了补丁更新,具体可看http://www.wdlinux.cn/bbs/thread- ...

  7. Solon rpc 之 SocketD 协议 - 消息鉴权模式

    Solon rpc 之 SocketD 协议系列 Solon rpc 之 SocketD 协议 - 概述 Solon rpc 之 SocketD 协议 - 消息上报模式 Solon rpc 之 Soc ...

  8. 【JDBC核心】数据库事务

    数据库事务 概述 事务是逻辑上的一组操作,或者说一个独立的工作单元.事务内的语句,要么全部执行成功,要么全部执行失败. 事务处理 数据一旦提交,就不可回滚.数据意味着提交的情况: 当一个连接对象被创建 ...

  9. 一条查询SQl是怎样执行的

    MySQL的逻辑架构图 大体来说,MySQL可以分为Server层和存储引擎层两部分. Server层包括连接器.查询缓存.分析器,优化器等,涵盖MySQL的大多核心服务功能,以及所有的内置函数,存储 ...

  10. 二进制格式 PLY 模型文件的读取与渲染

    PLY 文件头部信息: ply format binary_little_endian 1.0 comment VCGLIB generated element vertex 13469 proper ...