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

2-SAT学习笔记

时间:2024-02-12 16:22:05浏览次数:32  
标签:geq neg 笔记 学习 leq 等价 条件 SAT

2-SAT

k-SAT 问题
SAT是适定性(Satisfiability)问题的简称。一般形式为 k−适定性问题,简称k−SAT。而当k>2时该问题为NP完全的。所以我们只研究k=2的情况。
2−SAT,简单的说就是给出n个集合,每个集合有两个元素,已知若干个<a,b>,表示a与b矛盾(其中a与b属于不同的集合)。然后从每个集合选择一个元素,判断能否一共选n个两两不矛盾的元素。显然可能有多种选择方案,一般题中只需要求出一种即可

看看模板题

Description

有 \(n\) 个布尔变量 \(x_1∼x_n\) ,另有 \(m\) 个需要满足的条件,每个条件的形式都是 \(「xi 为 true / false 或 xj 为 true / false」\)。比如 「\(x1\) 为真或 \(x3\) 为假」、「 \(x7\) 为假或 \(x2\) 为假」。
2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。

Solution

我们发现,题目的要求是在两个条件中任选一个满足。也就是说,如果我们不选A条件,就必须要选B条件;同理,我们不选B条件,就必须要选A条件。
现在,我们假设边(A,B)表示选了A条件,就必须要选B条件。那么根据上面的推论,我们发现现在我们应该连边(非A条件,B条件),(非B条件,A条件)。
这个时候我们能发现,如果A条件和非A条件在同一个强连通分量里面,证明选了A条件之后我们就要选非A条件,这自相矛盾。这个时候无解。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2000010;
int n,m,x,y,a,b;
struct node{
	int to,nxt;
}e[N<<2];
int head[N],cnt;
int dfn[N],low[N],stk[N],tim,scc,vis[N],top,id[N];
void add(int u,int v)
{
	e[++cnt].to=v;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
void tarjan(int u)
{
	dfn[u]=low[u]=++tim;
	stk[++top]=u;
	vis[u]=1;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(vis[v]) low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u])
	{
		int v;
		++scc;
		do{
			v=stk[top--];
			vis[v]=0;
			id[v]=scc;
		}while(v!=u);
	}
}
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d %d %d %d",&x,&a,&y,&b);
		add(x+!a*n,y+b*n);
		add(y+!b*n,x+a*n);
	}
	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])
		{
			printf("IMPOSSIBLE\n");
			return 0;
		}
	}
	printf("POSSIBLE\n");
	for(int i=1;i<=n;i++)
	{
		if(id[i]<id[i+n]) printf("0 ");
		else printf("1 ");
	}
	return 0;
}

看看应用CF1697F

Description

构造一个长度为 \(n\) 的数列 \(a\) ,其中 \(1\leq a_i \leq k\) 且 \(a\) 不降,即对所有 \(1\leq i \leq n-1\) , \(a_i \leq a_{i+1}\) 。给出 \(m\) 个约束,有三种约束,其中:
\(1\) \(i\) \(x\) ,表示 \(a_i\neq x\)
\(2\) \(i\) \(j\) \(x\) ,表示 \(a_i+a_j\leq x\)
\(3\) \(i\) \(j\) \(x\) ,表示 \(a_i+a_j\geq x\)
现在有 \(t\) 组数据,要求你给出这个数列,无解输出 \(-1\) 。

Solution

断断续续调了3天的题,细节好多。
首先发现题目让我们通过好多限制寻找到一个可行解,考虑 2-SAT。2-SAT 的特点是每个变量只有两种取值,显然我们现在的 \(n\) 个数,每个数都有 \(k\) 种取值,怎么办呢,我们发现 \(2\leq k \leq 10\) , \(k\) 的值域非常小,那么我们把每个数都拆成 \(k\) 个点。这样我们一共只有 \(n*k\) 个点。其中 \(A_{i,j}\) 表示 \(a_i\geq j\)。
PS:这里之所以不定义成 \(A_{i,j}\) 表示 \(a_i=j\) 是因为
image
然后在回头看那 \(3\) 个限制

  1. \(a_i\neq x\) 等价于「若 \(a_i\geq x\) 则 \(a_i\geq x+1\)」
  2. \(a_i+a_j\leq x\) 等价于
    「\(\forall y\) 若 \(a_i\geq y\) 则 \(\neg(a_j\geq x-y+1)\) , \(\forall y\) 若 \(a_j\geq y\) 则 \(\neg(a_i\geq x-y+1)\)」
  3. \(a_i+a_j\geq x\) 等价于
    「\(\forall y\) 若 \(\neg(a_i\geq y)\) 则 \(a_j\geq x-y+1\) , \(\forall y\) 若 \(\neg(a_j\geq y)\) 则 \(a_i\geq x-y+1\)」

然而真的只有这 \(3\) 个限制吗,不是!

  1. 题目中说道 \(a\) 序列不降,即 \(a_i\leq a_{i+1}\) 等价于「\(\forall x\) 若 \(a_i\geq x\) 则 \(a_{i+1}\geq x\)」
  2. 还有最基本的「若 \(a_i\geq x\) 则 \(a_i\geq x-1\)」
  3. 还有更基本的 \(a_i\) 必须大于等于1,等价于「若 \(\neg(a_i\geq1)\) 则 \(a_i\geq1\)」

这就完啦?你别说你还真别说,还没有……
我们考虑一下前三条有没有什么问题,发现有大问题。

  1. 对于限制一,如果 \(x=k\) 显然 \(a_i\geq x\) 不可取但还没有 \(a_i\geq x+1\) 这个变量,所以等价于「若 \(a_i\geq x\) 则 \(\neg(a_i\geq x)\)」
  2. 对于限制二,如果 \(x<=k\) 可能会有 \(a_i=x\) \(a_j=0\) 或者 \(a_j=x\) \(a_i=0\) 的情况,这也不行,那么等价于「若 \(a_i\geq x\) 则 \(\neg(a_i\geq x)\) , 若 \(a_j\geq x\) 则 \(\neg(a_j\geq x)\)」
  3. 对于限制三,如果 \(x>k\) 要避免两个数有大于 \(k\) 的情况,也就是要避免有数小于 \(x-k\) 等价于「若 \(\neg(a_i\geq x-k)\) 则 \(a_i\geq x-k\) , 若 \(\neg(a_j\geq x-k)\) 则 \(a_j\geq x-k\)」

终于把限制写完了,另外由于 2-SAT 的对称性,上述所有条件的反向边也要连,注意这里的反向边不仅逻辑要反先后顺序也要反,这就不得不提到2-SAT中连边顺序的重要性,即满足……才……这样连一条有向边,反过来意思不同就错了。

太对了最后看看怎么输出答案,判断是否又解是好做的和模板题一样,关键是又解咋办捏,我们对于每个位置,从大到小枚举取值,如果可以就输出,这样选到的值一定是最大的,就避免了因为某个位置选的值小而使序列不满足序列不降这一条件。然后你终于做完了!

Code
另外很清晰的题解

Tricks

  1. 2-SAT的对称性,顺序不能反。

  2. 有多种取值且值域很小的时候考虑拆点。

  3. 限制不仅仅只有题中给的,找找隐藏限制2-SAT

标签:geq,neg,笔记,学习,leq,等价,条件,SAT
From: https://www.cnblogs.com/MarianaZ/p/18013956

相关文章

  • Vue3学习(16) - 左侧显示分类菜单
    写在前面和大家不太一样,我觉得今年的自己更加relax,没有亲戚要走,没有朋友相聚,也没有很好的哥们要去叙旧,更没有无知的相亲,甚至可以这么说没有那些闲得慌的邻居。也可以说是从今天开始,算是可以进入自己的小世界,做自己想做的事,看看书,学习一下。生活的精髓在于善待自己,用心感受每一......
  • 天下第一道的学习态度
    《18-天下第一道的学习态度》天下第一道的学习态度。天下第一道反对:两耳不闻窗外事,一心只读圣贤书,书呆子才这样做。天下第一道支持:风声雨声读书声,声声入耳,家事国事天下事,事事关心。天下第一道,要求人在求学阶段积极入世。直白点说就是一边学习,一边体验生活,观察生活,思考生活。体......
  • 【机器学习】数据清洗之处理缺失点
    ......
  • Python 机器学习 线性回归和岭回归
    ​ Python机器学习中,机器学习领域的线性回归和岭回归是两种常用的回归分析方法,用于预测一个或多个自变量(或称为特征)和因变量(或称为目标变量)之间的关系。这两种方法都试图找到最佳的线性组合来预测目标变量,但它们在处理数据的方法上有所不同。线性回归和岭回归都是常用的线性回......
  • 深度学习的始祖框架,grandfather级别的框架 —— Theano —— 示例代码学习(2)
    代码1:(ifelse判断结构)importtheanofromtheanoimporttensorfromtheano.ifelseimportifelsex=tensor.fscalar('x')y=tensor.fscalar('y')z=ifelse(x>0,2*y,3*y)#x>0的返回值是int8类型f=theano.function([x,y],z,allow_input_down......
  • 深度学习的始祖框架,grandfather级别的框架 —— Theano —— 示例代码学习(1)
    示例代码1:importtheanofromtheanoimporttensorx=tensor.vector("x")y=tensor.vector("y")w=tensor.vector("w")z=tensor.vector("z")z=x+y+wf=theano.function([x,theano.In(y,value=[1,1,1]),theano.In(......
  • 二十一、JS笔记
    JSONimportjson#对象转字符串str=json.dumps(dict,ensure_ascii=False)#ensure_ascii=True或不设置str=json.dumps(dict)#这时前端拿到的是未解码的数据:{"key1":"\u7528\u6237\u8f93...",...}obj=json.loads(str)#字符串转对象jsJSON.parse(str)#字符......
  • 大年初二学习SpringBoot之权限管理
    1增加spring-security依赖目前市面上主流的权限框架是:spring-security和shiro,shrio使用起来更简单,而spring-security的功能更强大。苏三商城项目选择的权限框架是:spring-security。首先要加入spring-security的相关依赖包。在项目中的pom.xml文件中增加如下依赖:<dependency......
  • 拉格朗日插值学习笔记
    拉格朗日插值第一步:子函数\(f_i(x)=\begin{cases}1&x=x_i\\0&x=x_j(i\nej)\end{cases}\)由此可得:\(f(x)=\sum\limits_{i=1}^ny_if_i(x)\)第二步:对于\(f_i(x)\),要满足当\(x=x_i\)时,\(y=1\),而\(x\nex_i\)时,\(y=0\)故:\(f_i(x)=\dfrac{\prod\limits_{j=1,j\......
  • Python 机器学习 线性回归 梯度下降法优化损失函数
    ​ Python机器学习中,梯度下降法是一种用于优化线性回归模型(以及其他机器学习算法)的损失函数的通用算法。目的是通过迭代地调整模型的参数(权重和截距),以最小化损失函数,例如均方误差(MSE)。梯度下降的基本思想是计算损失函数相对于每个参数的梯度(即偏导数),然后朝着减少损失的方向调......