2-SAT 学习笔记

2 − S A T 2-SAT 2SAT

类似题目

n n n个布尔变量,然后有一些约束条件:第 i i i个必须为真(假)或第 j j j个必须为真(假)。

解法

我们将这个关系建成一个图。
首先将第 i i i个点拆成 0 / 1 0/1 0/1状态,表示真或假。
如果选了 i i i必须得选 j j j时,那么连一条单向边 i i i j j j
但如果选了 i i i有很多可以选的话,就都不用连边。
自己可以画图试一试。
接着我们建了这个图。
如果有冲突,显然就是有环。
所以用 t a r j a n tarjan tarjan判环即可。

代码

#include<bits/stdc++.h>
#define N 4000005
using namespace std;
int n,m,to[N],la[N],ne[N],dfn[N],low[N],vis[N],col[N],sta[N],top,cnt,tot,sum;
void tarjan(int x){
	dfn[x]=low[x]=++tot;
	vis[x]=1;
	sta[++top]=x;
	for(int i=la[x];i;i=ne[i]){
		int y=to[i];
		if(!dfn[y]){
			tarjan(y);
			low[x]=min(low[x],low[y]);
		}
		else{
			if(vis[y]) low[x]=min(low[x],dfn[y]);
		}
	}
	if(dfn[x]==low[x]){
		int y=0;
		sum++;
		while(y^x){
			y=sta[top--];
			vis[y]=0;
			col[y]=sum;
		}
	}
}
void add(int u,int v){
	to[++cnt]=v;
	ne[cnt]=la[u];
	la[u]=cnt;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int p1,x1,p2,x2;
		scanf("%d%d%d%d",&p1,&x1,&p2,&x2);
		if(x1==0&&x2==0){
			add(p1+n,p2);
			add(p2+n,p1);
		}
		if(x1==0&&x2==1){
			add(p1+n,p2+n);
			add(p2,p1);
		}
		if(x1==1&&x2==0){
			add(p2+n,p1+n);
			add(p1,p2);
		}
		if(x1==1&&x2==1){
			add(p1,p2+n);
			add(p2,p1+n);
		}
	}
	for(int i=1;i<=(n<<1);i++)
		if(!dfn[i])
			tarjan(i);
	for(int i=1;i<=n;i++)
		if(col[i]==col[i+n]){
			printf("IMPOSSIBLE");
			return 0;
		}
	printf("POSSIBLE\n");
	for(int i=1;i<=n;i++)
		if(col[i]>col[i+n]) printf("1 ");
		else printf("0 ");
}

其它题目

题目描述

在这里插入图片描述
在这里插入图片描述

解题方法

枚举第一瓣的陌生度,二分枚举第二瓣的陌生度(假设第一瓣一定大于等于第二瓣),然后用 2 − S A T 2-SAT 2SAT判断一下。
这样可以40分。
然后考虑优化。
我们用并查集从大到小见图,然后判断环。

情况1

如果这是一个图的偶环,那么最短边不可能与答案有关,舍去。

情况2

如果这是一个图的奇环,那么最短边是最第一瓣陌生度的下界,也就是说,第一瓣的陌生度一定大于等于这条边,所以只要看大于等于它的边。

这就是优化,可以做到 O ( n 3 log ⁡ 2 n ) O(n^3\log_2^n) O(n3log2n)
听说好可以做到 O ( n 3 ) O(n^3) O(n3),不知道。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值