Tarjan在图论中的应用(三)——用Tarjan来求解2-SAT
前言
\(2-SAT\)的解法不止一种(例如暴搜?),但最高效的应该还是\(Tarjan\)。
说来其实我早就写过用\(Tarjan\)求解\(2-SAT\)的题目了(就是这道题:【2019.8.14 慈溪模拟赛 T2】黑心老板(gamble)),这篇博客本来已经石沉大海,打算坑掉了的,但由于在\(CSP-S\)前复习板子时忘记了这道题写法,结果板子题都挂了好几次,为了加深印象,为了自我惩罚,来补博客了。
基本模型
什么是\(2-SAT\)?
考虑有\(n\)个物品,每个物品有\(0\)和\(1\)两种取值。给出一些诸如第\(i\)个物品是\(0/1\)或第\(j\)个物品是\(0/1\)的限制,如:
- 第\(1\)个物品是\(0\)或第\(2\)个物品是\(1\)。
- 第\(1\)个物品是\(1\)或第\(3\)个物品是\(1\)。
- ......
而\(2-SAT\),就是求出一个满足所有条件的可行解,或是判断无解。
建图
既然提到要用\(Tarjan\)了,那么首先我们需要把这个问题转移到图上。
我们把每个物品看作两个点,分别表示这个物品取\(0\)和取\(1\)。
由于题目中给出的限制不是很明确,所以我们要先将它进行转化。
例如,若题目中给出第\(i\)个物品是\(x\)或第\(j\)个物品是\(y\)。
那么如果第\(i\)个物品是\(!x\),第\(j\)个物品就必须是\(y\)。反之,如果第\(j\)个物品是\(!y\),第\(i\)个物品就必须是\(x\)。
即,将\((i,!x)\)向\((j,y)\)连边,\((j,!y)\) 向\((i,x)\)连边。
求解
首先,我们考虑,如何判断已知的一组解\(ans\)的合法性。
不难发现,若能从\((i,ans_i)\)走到\((i,!ans_i)\),就说明这组解是不合法的。
这无疑带给我们一些启发。
如果存在\((i,0)\)与\((i,1)\)能互相到达,那么就是无解的。否则一定有解。
结合强连通分量的概念,即若\((i,0)\)与\((i,1)\)在同一个强连通分量中,就无解。
然后我们要考虑如何找到一组可行解。
如果\((i,0)\)所在的连通块能到达\((i,1)\),\(i\)就一定要选\(1\),反之亦然。
而能到达,一个必要条件就是缩点后拓扑序较小。
而要比较拓扑序,实际上也可以直接比较所在连通块缩点后的编号,根据\(Tarjan\)的原理,显然编号越小拓扑序越大。
因此我们只要选择编号较小的方案即可。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000000
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
#define Gmin(x,y) (x>(y)&&(x=(y)))
using namespace std;
int n,m,ee,lnk[2*N+5];struct edge {int to,nxt;}e[2*N+5];
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define pc(c) (C==E&&(clear(),0),*C++=c)
#define tn (x<<3)+(x<<1)
#define D isdigit(c=tc())
int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
public:
I FastIO() {A=B=FI,C=FO,E=FO+FS;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
Tp I void write(Con Ty& x,Con char& y) {write(x),pc(y);}
I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
namespace Tarjan//Tarjan缩点
{
int d,T,cnt,dfn[2*N+5],low[2*N+5],vis[2*N+5],S[2*N+5],col[2*N+5];
I void dfs(CI x,CI lst)//Tarjan
{
dfn[x]=low[x]=++d,vis[S[++T]=x]=1;
for(RI i=lnk[x];i;i=e[i].nxt)
!dfn[e[i].to]?(dfs(e[i].to,x),Gmin(low[x],low[e[i].to]))
:vis[e[i].to]&&Gmin(low[x],dfn[e[i].to]);
if(dfn[x]^low[x]) return;col[x]=++cnt,vis[x]=0;
W(S[T]^x) col[S[T]]=cnt,vis[S[T--]]=0;--T;
}
I void Solve()
{
RI i;for(i=1;i<=2*n;++i) !dfn[i]&&(dfs(i,0),0);//Tarjan
for(i=1;i<=n;++i) if(col[i]==col[n+i]) return (void)puts("IMPOSSIBLE");//判无解
for(puts("POSSIBLE"),i=1;i<=n;++i) F.write(col[i]>col[n+i]," \n"[i==n]);//输出一组可行解
}
}
int main()
{
RI i,a,b,c,d;for(F.read(n),F.read(m),i=1;i<=m;++i)
F.read(a),F.read(b),F.read(c),F.read(d),add(a+n*(!b),c+n*d),add(c+n*(!d),a+n*b);//建边
return Tarjan::Solve(),F.clear(),0;
}
Tarjan在图论中的应用(三)——用Tarjan来求解2-SAT的更多相关文章
- Tarjan在图论中的应用(二)——用Tarjan来求割点与割边
前言:\(Tarjan\) 求割点和割边建立在 \(Tarjan\)算法的基础之上,因此建议在看这篇博客之前先去学一学\(Tarjan\). 回顾\(Tarjan\)中各个数组的定义 首先,我们来回顾 ...
- Tarjan在图论中的应用(一)——用Tarjan来实现强连通分量缩点
前言 \(Tarjan\)是一个著名的将强连通分量缩点的算法. 大致思路 它的大致思路就是在图上每个联通块中任意选一个点开始进行\(Tarjan\)操作(依据:强连通分量中的点可以两两到达,因此从任意 ...
- 『图论』有向图强连通分量的Tarjan算法
在图论中,一个有向图被成为是强连通的(strongly connected)当且仅当每一对不相同结点u和v间既存在从u到v的路径也存在从v到u的路径.有向图的极大强连通子图(这里指点数极大)被称为强连 ...
- 转载:WinForm中播放声音的三种方法
转载:WinForm中播放声音的三种方法 金刚 winForm 播放声音 本文是转载的文章.原文出处:http://blog.csdn.net/jijunwu/article/details/4753 ...
- Jquery中each的三种遍历方法
Jquery中each的三种遍历方法 $.post("urladdr", { "data" : "data" }, function(dat ...
- C#中的线程三 (结合ProgressBar学习Control.BeginInvoke)
C#中的线程三(结合ProgressBar学习Control.BeginInvoke) 本篇继上篇转载的关于Control.BeginInvoke的论述之后,再结合一个实例来说明Cotrol.Begi ...
- C++中的异常处理(三)
C++中的异常处理(三) 标签: c++C++异常处理 2012-11-24 23:00 1520人阅读 评论(0) 收藏 举报 分类: 编程常识(2) 版权声明:本文为博主原创文章,未经博主允许 ...
- Linux内核中影响tcp三次握手的一些协议配置
在Linux的发行版本中,都存在一个/proc/目录,有的也称它为Proc文件系统.在 /proc 虚拟文件系统中存在一些可调节的内核参数.这个文件系统中的每个文件都表示一个或多个参数,它们可以通过 ...
- Google Chrome中的高性能网络 (三)
使用预连接优化了TCP连接管理 已经预解析到了主机名,也有了由OmniBox和Chrome Predictor提供信号,预示着用户未来的操作.为什么再进一步连接到目标主机,在用户真正发起请求前完成TC ...
随机推荐
- MySQL Aborted_clients和 Aborted_connects状态变量详解
Aborted_clients和 Aborted_connects状态变量详解 By:授客 QQ:1033553122 状态变量定义 Aborted_clients 因客户端消亡时未恰当的关闭连接 ...
- 【iOS13问题】修改状态栏的颜色(亲测,有效)
- (UIStatusBarStyle)preferredStatusBarStyle { if (@available(iOS 13.0, *)) { return UIStatusBarStyle ...
- Spring Boot Mybatis 最基本使用mysql存储过程
首先声明:只是用最简单的方法大致了解如何用存储过程开发,如果需要查看存储过程创建语法的自行百度搜索 一.首先创建最基本的数据库 CREATE TABLE `t_user` ( `id` varchar ...
- 利用Haproxy搭建 HTTP 请求走私(Request smuggling)环境
Haproxy 介绍 HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性.负载均衡,以及基于TCP和HTTP的应用程序代理. 请求走私(Request smuggling)概念证 ...
- Help Hanzo (LightOJ - 1197) 【简单数论】【筛区间质数】
Help Hanzo (LightOJ - 1197) [简单数论][筛区间质数] 标签: 入门讲座题解 数论 题目描述 Amakusa, the evil spiritual leader has ...
- VSCode 使用 ESLint + Prettier 来统一 JS 代码
环境: VSCode 1.33.1 Node.js 8.9.1 一.ESLint 1.介绍 ESLint是最流行的JavaScript Linter. Linter 是检查代码风格/错误的小工具.其他 ...
- idea实战技巧
一.背景 为什么想写这个,因为编码一线更多的是实战,实战中,可能一个快捷键,一个小技巧,就能省很多时间. 本文会持续记录,持续更新. 二.技巧 1.全局替换(带正则) 场景是: 多profile的情况 ...
- Java入门系列之类继承、抽象类、接口(五)
前言 C#和Java关于类.抽象类.接口使用方式基本相似,只是对应关键字使用不同罢了,本节呢,我们只是对照C#和Java中关于这三个概念在具体使用时,看看有哪些不一样的地方. 类继承 C#和Java在 ...
- IE浏览器远程代码执行高危漏洞(CVE-2019-1367)
IE浏览器远程代码执行高危漏洞(CVE-2019-1367)加固遇到的问题 一.背景介绍 Internet Explorer,是微软公司推出的一款网页浏览器.用户量极大.9月23日微软紧急发布安全更新 ...
- C# HttpClient 请求认证、数据传输笔记
目录 一,授权认证 二,请求类型 三,数据传输 C# HttpClient 请求认证.数据传输笔记 一,授权认证 客户端请求服务器时,需要通过授权认证许可,方能获取服务器资源,目前比较常见的认证方式有 ...