当前位置: 首页 > news >正文

【2-sat】2-sat算法内容及真题

A.2-sat简介

2-sat算法可以求解给定推出关系下的一种合法情况。题目中重常常,给定一些布尔变量A、B、C、D…,再给出一系列形如 B ⟶ A , C ⟶ ¬ D B \longrightarrow A , C \longrightarrow \neg D BA,C¬D的推出关系,询问使得所有推出关系都成立的一组布尔变量取值。

B.2-sat算法内容

1.无解情况

一个变量要么为真,要么为假,不能同时为真又为假。
如果 A ⟶ ¬ A A \longrightarrow \neg A A¬A,那该变量不能取值为真,因为,为真就触发矛盾
如果 ¬ A ⟶ A \neg A \longrightarrow A ¬AA,那该变量不能取值为假,因为,为假就触发矛盾
所以,如果 A ⟶ ¬ A A \longrightarrow \neg A A¬A ¬ A ⟶ A \neg A \longrightarrow A ¬AA,就找不到合法解。
其余情况有解。

2.构造合法解

尝试贪心地构造一组合法解。
观察这样一组情况
A ⟶ ¬ B ⟶ C ⟶ ¬ A ⟶ D ⟶ B A \longrightarrow \neg B\longrightarrow C\longrightarrow \neg A\longrightarrow D \longrightarrow B A¬BC¬ADB
由于关系的传递性,

  • 如果A为真,后面5个变量都要合法,即 B为假,C为真,A为假,D为真,B为真。不难发现,A为真且为假,B为真且为假,矛盾。
  • 如果A为假,只需最后3个变量合法,即D为真,B为真。

得出结论,对于变量A,选择拓扑序靠后一个,更优。具体一些,严格优于另一个。
推广到一般,对于任意变量X,选择拓扑序靠后的取值为答案中的值。

3.算法实现

  1. 首先,需要建图。假设共有n个变量,点 1,2,3…n表示变量为真情况,点 1 + n,2 + n,…n+n表示变量为假的情况。对于第 i 个变量,点 i 表示该变量为真, 点 i + n表示该变量为假。往每个点中存入由该点能推出的点,例如,
  • 变量 n 为真 推出 变量 1 为真,则往点n中存入1;
  • 变量 n 为真 推出 变量 1 为假,则往点n中存入 1 + n;
  • 变量 n 为假 推出 变量 1 为假,则往点n + n中存入 1
  1. 判断无解情况,对整个图求强联通分量,如果 i 与 i + n在一个强联通分量内部,则存在上文所说的 “ A ⟶ ¬ A A \longrightarrow \neg A A¬A ¬ A ⟶ A \neg A \longrightarrow A ¬AA”,则无解。
  2. 如果有解,对每个变量,输出拓扑序靠后的一个,即强联通分量编号小的一个(tarjan算法的性质)。
\\tarjan
const int N = 1e6 + 10;
int dfn[N],low[N],cnt;
stack<int> stk;
bool ins[N];
int id[N],scc_cnt,sz[N];
vector<int> g[N];
int n,m;void tarjan(int u)
{dfn[u] = low[u] = cnt ++;stk.push(u);ins[u] = 1;for(auto j : g[u]){if(!dfn[j]){tarjan(j);low[u] = min(low[u],low[j]);}else if(ins[j]){low[u] = min(low[u],dfn[j]);}}if(dfn[u] == low[u]){int y;++scc_cnt;do{y = stk.top();stk.pop();ins[y] = 0;id[y] = scc_cnt;sz[scc_cnt] ++;}while(y != u);}
}
	\\判断有无解for(int i = 1; i <= 2*n; i ++){if(!dfn[i]) tarjan(i);}for(int i = 1; i <= n; i ++){if(id[i] == id[i+n]){cout << "NO\n";return;}}
	\\存储答案vector<int> ans;for(int i = 1; i <= n; i ++){if(id[i] < id[i + n])ans.push_back(i);}

例题 P4782 【模板】2-SAT

题目描述

n n n 个布尔变量 x 1 ∼ x n x_1\sim x_n x1xn,另有 m m m 个需要满足的条件,每个条件的形式都是 「 x i x_i xitrue / false x j x_j xjtrue / false」。比如 「 x 1 x_1 x1 为真或 x 3 x_3 x3 为假」、「 x 7 x_7 x7 为假或 x 2 x_2 x2 为假」。

2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。

输入格式

第一行两个整数 n n n m m m,意义如题面所述。

接下来 m m m 行每行 4 4 4 个整数 i i i, a a a, j j j, b b b,表示 「 x i x_i xi a a a x j x_j xj b b b」( a , b ∈ { 0 , 1 } a, b\in \{0,1\} a,b{0,1})

输出格式

如无解,输出 IMPOSSIBLE;否则输出 POSSIBLE

下一行 n n n 个整数 x 1 ∼ x n x_1\sim x_n x1xn x i ∈ { 0 , 1 } x_i\in\{0,1\} xi{0,1}),表示构造出的解。

输入输出样例 #1

输入 #1

3 1
1 1 3 0

输出 #1

POSSIBLE
0 0 0

说明/提示

1 ≤ n , m ≤ 1 0 6 1\leq n, m\leq 10^6 1n,m106 , 前 3 3 3 个点卡小错误,后面 5 5 5 个点卡效率。

由于数据随机生成,可能会含有( 10 0 10 0)之类的坑,但按照最常规写法的写的标程没有出错,各个数据点卡什么的提示在标程里。

思路

  • A ∨ B ⟺ ¬ A ⟶ B , ¬ B ⟶ A A\vee B \Longleftrightarrow \neg A\longrightarrow B,\neg B\longrightarrow A AB¬AB,¬BA

练习

【2018ICPC首尔区域赛】
【2023ICPC济南区域赛】
【2023ICPC网络预选赛(2)】

相关文章:

  • IBM WebSphere Liberty产品简介
  • ReLU函数及其Python实现
  • 【业务领域】InfiniBand协议总结
  • 【C++贪心】P8411 「SvR-1」Problem|普及
  • 亚马逊云服务器性能深度优化方案(2025版)
  • Aws S3上传优化
  • Spring MVC @RequestHeader 注解怎么用?
  • 第5篇:EggJS中间件开发与实战应用
  • 【学习笔记】深入理解Java虚拟机学习笔记——第2章 Java内存区域与内存溢出异常
  • JavaScript性能优化实战之运行时性能优化
  • gRPC学习笔记记录以及整合gin开发
  • 云原生后端:构建高效、可扩展的现代后端架构
  • JVM——JVM 是如何执行方法调用的?
  • NFS 快速开始
  • React的patch流程
  • MySQL基本查询(二)
  • Python清空Word段落样式的方法
  • 【iOS】类与对象底层探索
  • 2025年- H20-Lc128-240. 搜索二维矩阵 II(矩阵)---java版
  • Qt 项目代码解释(4)
  • 马上评|提供情绪价值,也是文旅经济的软实力
  • 市场驱动的系统改造:丹麦零弃风经验研究
  • 美国防部监察机构扩大“群聊门”事件调查范围
  • 永辉超市回应顾客结算时被“反向抹零”:整改并补偿
  • 4月一二线城市新房价格环比上涨,沪杭涨幅居百城前列
  • 白玉兰奖征片综述丨国产剧集创作的此消彼长