2-SAT

Defination

  • k-SAT问题 :通俗的可以理解为, 对于 n n n个集合,每个集合有 k k k个元素,集合内元素只能有一个为 1 1 1,集合的元素间有限制。
    -类型: NP
  • 2-SAT: [ k = = 2 ] [k==2] [k==2],类型:P

Algorithm

1.对每个 i i i,有 i 0 , i 1 i_0,i_1 i0,i1,表示 i i i选0或1。

2.题目的限制( i , j i,j i,j至少一个为1, i , j i,j i,j只有一个为1…),转化为 : i k − > j p , j p   x o r   1 − > i k   x o r   1 i_k- > j_p,j_{p\ xor\ 1}->i_{k\ xor\ 1} ik>jp,jp xor 1>ik xor 1

3.对 2 ∗ n 2*n 2n个点建有向图,跑 t a r j a n tarjan tarjan强连通分量缩点。

4.若 ∃   i 0 , i 1 \exist\ i_0,i_1  i0,i1在同一强连通分量,则原问题无解。

5.否则,原问题有解(解的数目不确定)

6.证明有解: 直接从构造方式证明:
∀   i , { c h o o s e   i 0 d f n [ i 0 ] < d f n [ i 1 ] c h o o s e   i 1 d f n [ i 1 ] < d f n [ i 0 ] \forall \ i, \begin{cases} choose\ i_0 & dfn[i_0]<dfn[i_1] \\ choose\ i_1 & dfn[i_1]<dfn[i_0] \\ \end{cases}  i,{choose i0choose i1dfn[i0]<dfn[i1]dfn[i1]<dfn[i0]
-6.1 i i i自身不矛盾。

-6.2 i i i不会让 j j j矛盾。
i k − > j k − > . . . − > j k   x o r   1 i_k->j_k->...->j_{k\ xor\ 1} ik>jk>...>jk xor 1,根据建图的对称性( i k − > j p , j p   x o r   1 − > i k   x o r   1 i_k- > j_p,j_{p\ xor\ 1}->i_{k\ xor\ 1} ik>jp,jp xor 1>ik xor 1 ),有 j k   x o r   1 − > i k j_{k\ xor\ 1}->i_k jk xor 1>ik,矛盾。

-6.3 i k   ! − >   i k   x o r   1 & &   i k   x o r   1   ! − > i k i_k \ !->\ i_{k\ xor\ 1} \And\And\ i_{k\ xor\ 1}\ !->i_k ik !> ik xor 1&& ik xor 1 !>ik,任选其一。(10.20)

-6.4解的数量是: 2 c n t 自 由 元 2^{cnt_{自由元}} 2cnt(10.20)


Application

1.找到 两 元 性 两元性 ,即 对于每一个元素,两种状态有且仅有一种成立。

2.构造元素间约束关系。


EXAMPLES

1.WOJ#4586 逻辑命题
在这里插入图片描述

  • 每个命题 t r u e / f l a s e true/flase true/flase,为2元,转化至少一个成立: 一个成立,另一个一定成立(由对称性,“至少一个成立”转化成 4 条边。但实际上重合了,只有2条边。)

  • 直接 2 − s a t 2-sat 2sat,看 i 0 i_0 i0 i 1 i_1 i1能否互相推出即可。

#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define file freopen("data.in","r",stdin); 
const int N=1e5+10;
int cnt=0,head[N],nxt[N],to[N],n,m,con[1005][1005];
inline void _add(int u,int v){
	nxt[++cnt]=head[u];head[u]=cnt;to[cnt]=v;
}
int dfn[N],low[N],col[N],CN=0,tim=0,zhn[N],top=0,vis[N];
inline int idx(int x){
	return x>n? x-n:x+n;
}
bool dfs(int u){
	if(col[u]==2)return 1;
	col[u]=1;col[idx(u)]=2;
	for(int i=head[u];i;i=nxt[i])if(col[to[i]]!=1)if(dfs(to[i]))return 1; 
}
int ans[N];
signed main(){
	sf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		char a,b;int x,y;
		sf("\n%d %c %d %c",&x,&a,&y,&b);
		_add(a=='N'? x : idx(x),b=='N'? idx(y) : y);
		_add(b=='N'? y : idx(y),a=='N'? idx(x) : x);
	}
	for(int i=1;i<=n;++i){
		int f1=0,f2=0;
		memset(col,0,sizeof col);
		f1=dfs(i);
		memset(col,0,sizeof col);
		f2=dfs(idx(i));
		if(f1&&f2){
			cout<<"IMPOSSIBLE";
			return 0;
		}
		if(!f1&&f2){
			ans[i]=1;
		}
		if(f1&&!f2){
			ans[i]=2;
		}
		if(!f1&&!f2){
			ans[i]=3;
		}
	}
	for(int i=1;i<=n;++i){
		if(ans[i]==1)cout<<"Y";
		if(ans[i]==2)cout<<"N";
		if(ans[i]==3)cout<<"?";
	}
//	bfs();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值