Luogu P4782 【模板】2-SAT 问题(2-SAT)
题意
题目背景
\(2-SAT\)问题模板
题目描述
有\(n\)个布尔变量\(x_1\sim x_n\),另有\(m\)个需要满足的条件,每个条件的形式都是“\(x_i\)为\(true/false\)或\(x_j\)为\(true/false\)”。比如“\(x_1\)为真或\(x_3\)为假”、“\(x_7\)为假或\(x_2\)为假”。\(2-SAT\)问题的目标是给每个变量赋值使得所有条件得到满足。
输入输出格式
输入格式:
第一行两个整数\(n\)和\(m\),意义如题面所述。
接下来\(m\)行每行\(4\)个整数\(i\ a\ j\ b\),表示“\(x_i\)为\(a\)或\(x_j\)为\(b\)”\((a,b\in \{ 0,1\} )\)
输出格式:
如无解,输出"IMPOSSIBLE"
(不带引号); 否则输出"POSSIBLE"
(不带引号),下一行\(n\)个整数\(x_1\sim x_n(x_i\in \{ 0,1\} )\),表示构造出的解。
输入输出样例
输入样例#1:
3 1
1 1 3 0
输出样例#1:
POSSIBLE
0 0 0
思路
快学\(2-SAT\),这样你就可以做[NOI2017]游戏这道水题了。 --huyufeifei
\(2-SAT\)问题是我很喜欢的一类问题,一是因为它使用了我很喜欢的\(Tarjan\)算法
,二是它使用逻辑判断的方式实现的算法,这也是很使我喜欢的。
对于每一个\(x_i\)我们建两个点,编号为\(i\)和\(i+n\),\(i\)表示\(x_i=1\)的情况,\(i+n\)表示\(x_i=0\)的情况。接下来考虑对于每一对逻辑关系建边。在这里,为了问题的普适性,我们不止考虑题目列出的条件,来试着考虑更多的情况。
- \(a\)为真:建立一条边\((a+n,a)\),表示如果\(a\)为假,则\(a\)为真。这样就可以最终推得\(a\)为真的情况。
- 如果\(a\)为真,则\(b\)为假:建立两条边:\((a,b+n),(b,a+n)\)。
- \(a\)为真与\(b\)为假至少满足一个:建立两条边:\((a+n,b+n),(b,a)\)。
- \(a\)为真与\(b\)为假不能同时满足:建立两条边:\((a,b),(b+n,a+n)\)。
还有很多的情况没有枚举,不过它们与上述内容形似,在这里就不做列举了。
接下来怎么办呢?根据我们连边的方式,不难发现边的意义为推导出,也就是说,如果\(a\)能通过某些路径到达\(b\),这表示的意义就是\(a\)能通过某些条件推导出\(b\),那么如果我们让\(a\)满足,\(b\)就一定要被满足。如果\(a,b\)能够互达,就说明这两者要么同时被满足,要么同时不被满足。
不难想出,有且仅有一种情况无解:\(a\)与\(a+n\)可以互达,也就是两个互相矛盾的条件可以互相推导出。使用\(Tarjan\)缩点,这样可以快速求出任意两点是否可以互相到达,也就可以判断出解的存在性。
如何决定各个变量的取值呢?如果能从\(a\)推导出\(a+n\),我们显然不能选择\(a\),而只能选择\(a+n\)。所以对于同一个变量的两个取值,我们要检查其是否有推导的关系。根据\(Tarjan\)算法的特性,如果\(a\)能到达\(b\)且\(a,b\)不在同一缩出的点中,那么\(b\)缩点之后所在点的编号一定小于\(a\)。如果\(a\)不能到达\(b\),那么两者的缩点编号不好判断。当然,既然只需要得出任意一组解,对于每一对\((a,a+n)\),我们就输出其缩点编号小的即可。
AC代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e6+5;
int n,m,tot,dfn[MAXN],low[MAXN];
int cnt,top[MAXN],to[MAXN],nex[MAXN];
int js,bel[MAXN];
bool vis[MAXN];
stack<int>S;
int read()
{
int re=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
return re;
}
void add_edge(int x,int y){to[++cnt]=y,nex[cnt]=top[x],top[x]=cnt;}
void tarjan(int now)
{
dfn[now]=low[now]=++tot,vis[now]=true;
S.push(now);
for(int i=top[now];i;i=nex[i])
if(!dfn[to[i]]) tarjan(to[i]),low[now]=min(low[now],low[to[i]]);
else if(vis[to[i]]) low[now]=min(low[now],dfn[to[i]]);
if(dfn[now]==low[now])
{
bel[now]=++js,vis[now]=false;
while(S.top()!=now) bel[S.top()]=js,vis[S.top()]=false,S.pop();
S.pop();
}
}
int main()
{
n=read(),m=read();
while(m--)
{
int x=read(),xx=read(),y=read(),yy=read();
if(xx&&yy) add_edge(x+n,y),add_edge(y+n,x);
else if(xx&&!yy) add_edge(x+n,y+n),add_edge(y,x);
else if(!xx&&yy) add_edge(x,y),add_edge(y+n,x+n);
else if(!xx&&!yy) add_edge(x,y+n),add_edge(y,x+n);
}
for(int i=1;i<=(n<<1);i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++)
if(bel[i]==bel[i+n])
{
printf("IMPOSSIBLE");
return 0;
}
puts("POSSIBLE");
for(int i=1;i<=n;i++) printf("%d ",bel[i]<bel[i+n]);
return 0;
}
Luogu P4782 【模板】2-SAT 问题(2-SAT)的更多相关文章
- [luogu P3384] [模板]树链剖分
[luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点 ...
- Luogu P2742 模板-二维凸包
Luogu P2742 模板-二维凸包 之前写的实在是太蠢了.于是重新写了一个. 用 \(Graham\) 算法求凸包. 注意两个向量 \(a\times b>0\) 的意义是 \(b\) 在 ...
- luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)
luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include< ...
- Luogu [P3367] 模板 并查集
[模板]并查集 题目详见:[[P3367][模板]并查集] (https://www.luogu.org/problemnew/show/P3367) 这是一道裸的并查集题目(要不然叫模板呢) 废话不 ...
- Luogu P3381 (模板题) 最小费用最大流
<题目链接> 题目大意: 给定一张图,给定条边的容量和单位流量费用,并且给定源点和汇点.问你从源点到汇点的最带流和在流量最大的情况下的最小费用. 解题分析: 最小费用最大流果题. 下面的是 ...
- 51: Luogu 2485 模板
$des$ 1.给定y.z.p,计算y^z mod p 的值: 2.给定y.z.p,计算满足xy ≡z(mod p)的最小非负整数x: 3.给定y.z.p,计算满足y^x ≡z(mod p)的最小非负 ...
- [Luogu] 【模板】点分治1
// 模板题#include <bits/stdc++.h> ; , head[N], dis[N]; ]; int size[N], maxson[N], Root; bool vis[ ...
- luogu P5410 模板 扩展 KMP Z函数 模板
LINK:P5410 模板 扩展 KMP Z 函数 画了10min学习了一下. 不算很难 思想就是利用前面的最长匹配来更新后面的东西. 复杂度是线性的 如果不要求线性可能直接上SA更舒服一点? 不管了 ...
- luogu P4887 模板 莫队二次离线 莫队 离线
LINK:模板莫队二次离线 很早以前学的知识点 不过 很久了忘了. 考虑暴力 :每次莫队更新的时候 尝试更新一个点到一个区间的答案 可以枚举二进制下位数为k的数字 看一下区间内的这种数字有多少个. 不 ...
随机推荐
- CIE XYZ
了解CIE XYZ的来龙去脉,看维基之前,先读这两篇文章: https://medium.com/hipster-color-science/a-beginners-guide-to-colorime ...
- CSS——before和after伪元素
之所以被称为伪元素,是因为他们不是真正的页面元素,html没有对应的元素,但是其所有用法和表现行为与真正的页面元素一样,可以对其使用诸如页面元素一样的css样式,表面上看上去貌似是页面的某些元素来展现 ...
- 专访阿里云MVP王俊杰:开发者的超能力是用技术让世界更美好
[王俊杰:阿里云MVP,陕西创博网络科技有限公司总经理.大数据与物联网的爱好者与实践者. 8年以上互联网从业经验,曾从事军工相关仿真分析软件研发与集成.4年以上大数据系统开发经验.目前正与天水市秦州区 ...
- luoguP1062 数列 [数学]
题目描述 给定一个正整数k(3≤k≤15),把所有k的方幂及所有有限个互不相等的k的方幂之和构成一个递增的序列,例如,当k=3时,这个序列是: 1,3,4,9,10,12,13,… (该序列实际上就是 ...
- 缓冲(cache)和缓存(buffer)
缓存: 指把常用数据存储到可以快速获取的区域,以备重复利用 一般叫做cache. 缓存能提高效率 缓冲: 是指在数据流转过程中,不同层次速度不一致时,利用缓冲区来缓解上下层之间速率问题(性能差异) 一 ...
- VMware下CentOS6.5无法连接网络
VMware下CentOS6.5无法连接网络的主要原因就是eth0文件配置了不正确的地址 正确配置方法如下: 1.确保虚拟网卡(VMware Network Adapter VMnet8)是开启的,然 ...
- MDK(KEIL)使用Astyle格式化代码
关于Astyle Astyle 的全称是Artistic Style的简称,是一个开源的源代码格式化工具,可以对C,C++,C#以及Java等编程语言的源代码进行缩进.格式化.美化. Home Pag ...
- 使用串口绘制实时曲线 —— SerialChart
SerialChart:下载 1. 实验效果 2. 串口程序 ){ ){ y = ; x = ; } ) y++; else y--; z = sin(x*Pi/); p = cos(x*Pi/); ...
- day 84 Vue学习之vue-cli脚手架下载安装及配置
Vue学习之vue-cli脚手架下载安装及配置 1. 先下载node.js,下载地址:https://nodejs.org/en/download/ 找个目录保存,解压下载的文件,然后配置环境变量 ...
- TKmybatis的框架介绍和原理分析及Mybatis新特性演示
tkmybatis是在mybatis框架的基础上提供了很多工具,让开发更加高效,下面来看看这个框架的基本使用,后面会对相关源码进行分析,感兴趣的同学可以看一下,挺不错的一个工具 实现对员工表的增删改查 ...