首页 > 其他分享 >2-SAT 学习笔记

2-SAT 学习笔记

时间:2024-09-26 21:24:04浏览次数:1  
标签:int neg 复杂度 笔记 学习 算法 rightarrow SAT

2-SAT 学习笔记

本文同载于本人的洛谷文章。

参考资料

算法

2-SAT 用于解决什么样的问题?

问题

给定 \(n\) 个大小为 2 的集合,每个集合要选其中一个元素,不能同时选,有 \(m\) 个条件 \((a,b)\) 代表元素 \(a,b\) 不能同时选,构造方案或判定无解。

例子

有 3 个集合:\(\{a,\neg a\},\{b,\neg b\},\{c,\neg c\}\),条件 \((a,\neg b),(\neg b ,\neg c)\)。

解法

因为集合内不能同时选,所以集合内的两个元素我们互相取反。

把每个元素当成一个点,即把 \(\{a,\neg a\}\) 分成两个点。

现在我们连有向边,每条边 \(a\) 连向 \(b\) 代表当 \(a\) 选时 \(b\) 也一定选。

因为每个集合选一个元素,即不能同时选择。

所以对于条件 \((a,b)\),若 \(a\) 为真,则 \(\neg b\) 为真,反之同理。

于是我们连好边了,然后求用 \(Tarjan\) 强连通分量。

此时若 \(\neg a\) 和 \(a\) 在同一个强连通分量内,则无解。

然后构造解,考虑按照拓扑序。

例如有 \(a\rightarrow b \rightarrow \neg a\),则我们应该选 \(\neg a\) 而不应该选 \(a\)。

所以我们要按照拓扑序从大到小选择,但我们不用真的拓扑排序,我们求强连通分量时缩点的编号就是反着的拓扑序。

于是对于 \(\{a,\neg a\}\) 我们把拓扑序大的选择(缩点后编号小的选择)。

有 \(O(m)\) 条边,\(O(n)\) 个点,跑 \(Tarjan\) 是 \(O(n+m)\) 的。

模板题

P4782 2-SAT 模板

注意这道题是"\(x_i\) 为 \(a\) 或 \(x_j\) 为 \(b\)",即两个至少有一个满足条件,即 \(x_i=\neg a\) 和 \(x_j=\neg b\) 不能同时存在,于是就转化成了上面所说的条件了。

其实就是 \(a \lor b=\neg ((\neg a)\land (\neg b))\)

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m;
const int N=2e6+5;
int stk[N],bz[N],dfn[N],low[N],num,dfn1,top;
vector<int> g[N];
int neg(int x){
	if(x<=n)return x+n;
	return x-n;
}
int nm[N];
void dfs(int x){
	dfn[x]=low[x]=++dfn1,bz[x]=1,stk[++top]=x;
	for(int v:g[x]){
		if(!dfn[v]) dfs(v),low[x]=min(low[v],low[x]);
		else if(bz[v]) low[x]=min(dfn[v],low[x]);
	}
	if(dfn[x]==low[x]){
		++num;
		while(stk[top]!=x)nm[stk[top]]=num,bz[stk[top]]=0,top--;
		nm[x]=num,bz[x]=0,top--;
	}
}
int ans[N];
int main(){
//	freopen("2-sat.in","r",stdin);
//	freopen("2-sat.out","w",stdout);
	ios::sync_with_stdio(0); cin.tie(0);
	cin>>n>>m;
	for(int _i=1;_i<=m;_i++){
		int i,a,j,b;
		cin>>i>>a>>j>>b;
		a^=1,b^=1;
		if(!a)i=neg(i);
		if(!b)j=neg(j);
		g[i].push_back(neg(j));
		g[j].push_back(neg(i));
	}
	for(int i=1;i<=2*n;i++){
		if(!dfn[i])dfs(i);	
	}
	for(int i=1;i<=n;i++){
		if(nm[i]==nm[neg(i)]){
			cout<<"IMPOSSIBLE";
			return 0;
		}
		if(nm[i]<nm[neg(i)])ans[i]=1;
	}
	cout<<"POSSIBLE\n";
	for(int i=1;i<=n;i++){
		cout<<ans[i]<<" ";
	}
}

本质思想

其实就是每个位置二选一,同时连边表示选了一个另一个必须选。

最后跑强连通分量求拓扑序,同时判断是否无解。

用这个思路可以应用在很多题目上。

注意:连边关系一定要列全,否则最后的答案可能不满足约束条件。

习题

jzoj 8097

P3209 [HNOI2010] 平面图判定

因为给出的环包括了 \(n\) 个点,所以我们只用考虑除了环以外的边。

对于一条边,它可以在环内或环外,而它又不能与其他边相交。

这就是每个点选 0 或 1,同时有些边不能同时选 0 或 1,这可以用 2-SAT 来做。

我们重新标号,则对于 \(a<x<b<y\) 的边 \((a,b),(x,y)\) 不能选在同一边。

乍一看这个东西几乎不可做,直接做是 \(O(m^2)\) 的,过不了。

但是平面图有性质,即 \(m\le 3*n-6\),\(m\) 为边数,\(n\) 为点数。

于是对于不满足性质的直接判掉,此时 \(m\) 与 \(n\) 同阶,连边时间复杂度为 \(O(n^2)\)。

每条边分成两个点跑 2-SAT,由于 \(m\) 与 \(n\) 同阶,所以复杂度为 \(O(n)\)。

总时间 \(O(T(n^2+m))\)。

P3825 [NOI2017] 游戏

算法 1

如果 \(x\) 的个数为 0,则每个位置都是二选一,再带上一些限制,这是 2-SAT 板子题。

建边方式:

设题目所给条件为若 \(u\) 选了,则 \(v\) 必须选。

先看若 \(u\) 存在而 \(v\) 不存在,则 \(u\) 不能选,于是连边 \(u\rightarrow u'\),就能使只能选 \(u'\)。

若 \(u\) 和 \(v\) 都存在:

  • 先连边 \(u\rightarrow v\),即 \(u\) 选了后 \(v\) 必须选。

  • 再连边 \(v'\rightarrow u'\),即选 \(v'\),则不选 \(v\),则 \(u\) 不能选,则选 \(u'\)。

判断有无解和构造方案与 2-SAT 板子一样。

期望得分 45 pts。

算法 2

我们可以 \(O(3^d)\) 枚举每个 \(x\) 的位置是选 \({A,B,C}\) 中的一种,对于剩下的部分做算法 1。

时间复杂度 \(O(3^d(n+m))\)。

期望得分 80 pts。

算法 3

考虑直接转化为对所有点的 2-SAT。

我们可以 \(O(3^d)\) 枚举每个 \(x\) 是 \(\{A,B\},\{A,C\},\{B,C\}\) 中的一种二选一,之后就如算法 1。

时间复杂度 \(O(3^d(n+m))\),不能通过。

期望得分 80 pts。

算法 4

考虑改进算法 3。

对于每个 \(x\),只需枚举 \(\{A,B\},\{B,C\}\) 就可以覆盖 \(x\) 的所有可选的方案了。

也就是每个 \(x\) 只用枚举两种二选一。

时间复杂度 \(O(2^d(n+m))\)。

期望得分 100 pts。

标签:int,neg,复杂度,笔记,学习,算法,rightarrow,SAT
From: https://www.cnblogs.com/dccy/p/18434418

相关文章

  • Python从0到100(五十八):机器学习-随机森林及对复杂数据集分类
    随机森林通过构建多个决策树来完成分类或回归任务。随机森林的核⼼思想是通过多个弱学习器(决策树)的集成来构建⼀个强学习器,从⽽提⾼模型的泛化能⼒和稳定性。1.基本原理随机森林的基本原理如下:从训练集中随机抽取⼀定数量的样本(有放回抽样),构建⼀个决策树(称为⾃助采样法或......
  • 卷积神经网络-迁移学习
    文章目录一、迁移学习1.定义与性质2.步骤二、BatchNormalization(批次归一化)三、ResNet网络1.核心思想2.残差结构(1)残差块(2)残差结构类型四、总结一、迁移学习迁移学习(TransferLearning)是一种强大的机器学习方法,其核心思想是将在一个任务(源任务)上学到的知识或模型......
  • 深度学习:ResNet残差神经网络
    目录一、什么是ResNet残差神经网络二、残差结构三、18层残差网络1.最初残差网络变体2.图片示例3.表格示例四、批次归一化(BatchNormalization)1.工作过程2.主要作用五、ResNet残差神经网络解决了传统神经网络什么问题1.梯度消失和梯度爆炸梯度消失:梯度爆炸:2.退化......
  • 【刷题笔记】2019 CSP-J
    2019CSP-J题目整理B-公交换乘思路梳理先想暴力算法,一遇到公交车,就在已出现过的优惠卷中寻找价格大于等于公交车票价,并且出现时间最早且没有用过的优惠卷,时间复杂度为\(O(n^2)\),必然会炸。但是注意题目中给到的特殊性质,要求如果优惠卷有效,则\[t_{bus}-t_{subway}\le45\]并......
  • 利用大规模无监督学习提升药物分子表示
    人工智能咨询培训老师叶梓转载标明出处在人工智能驱动的药物设计和发现领域,获取具有信息量的分子表示是一个至关重要的前提。近年来,研究者们将分子抽象为图,并利用图神经网络(GNNs)进行分子表示学习,展现出了巨大的潜力。然而,实际应用中GNNs面临着两个主要问题:一是用于监督训练的......
  • JavaWeb基础-学习笔记01
    01JavaWeb介绍一个Web的互联网系统可以分为三个主要部分:网页、JavaWeb程序、数据库网页:展现数据数据库:存储和管理数据javaWeb程序:逻辑处理因此,JavaWeb的学习内容对应以上三部分内容:数据库部分MySQL:一款主流的数据库产品(数据库管理系统),用结构化查询语言SQL操作数据库JD......
  • Java中集合工具类的学习
    集合工具类目录集合工具类Collections类Arrays类Comparator接口总结Java中的集合工具类主要帮助开发者对集合(如List、Set、Map等)进行高效的操作和管理。虽然“三种集合工具类”这一表述可能不完全精确,因为Java集合框架中包含了多个工具类和接口,但我可以根据常见的和重要的工具......
  • repo 简单搭建学习记录
    repo简单搭建学习记录一、repo搭建参考:repo仓库搭建教程【CSDN】gitrepo工具详细使用教程【CSDN】搭建Repo服务器【CSDN】使用REPO管理GIT多仓库1、服务端repo需要一个服务端(manifest仓库),用来列出所有子仓库的路径等信息,如果在github等远程托管平台创建服务端,那......
  • 学习技巧: word文档中写论文会需要的技巧
    之前经常给大家分享办公技巧,今天想给大学生朋友分享一些写论文时候会用到的技巧。技巧一:图片、表格编号及引用论文中少不了图片、表格,而且还需要进行编号,如果我们纯靠自己手动输入,我们需要调节位置还有字体大小什么的,但是我们可以自动编号。方法如下:首先我们先插入图片,右键......
  • [深度学习]卷积神经网络CNN
    1图像基础知识importnumpyasnpimportmatplotlib.pyplotasplt#图像数据#img=np.zeros((200,200,3))img=np.full((200,200,3),255)#可视化plt.imshow(img)plt.show()#图像读取img=plt.imread('img.jpg')plt.imshow(img)plt.show()2CNN概述卷积层conv+......