2-SAT问题

2-SAT问题

n 个布尔变量 x1xn,另有 m 个需要满足的条件,每个条件的形式都是 「xitrue / falsexjtrue / false」。比如 「x1 为真或 x3 为假」、「x7 为假或 x2 为假」。

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

求出构造出来的解(若无解输出POSSIBLE)

输入格式

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

接下来 m 行每行 4 个整数 i, a, j, b,表示 「xiaxjb」(a,b{0,1})

输出格式

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

下一行 n 个整数 x1xnxi{0,1}),表示构造出的解。

样例 #1

样例输入 #1

3 1
1 1 3 0

样例输出 #1

POSSIBLE
0 0 0

解法

我们考虑建图,把 x1false 设成 1 号点,x1true 设成 n+1 号点。

假如一个条件中可以建成一些边:

例如条件a 0 b 0

就代表要么a = false要么b = false

那么很容易可以知道

如果 a = true 那么一定有 b = false

如果 b = true 那么一定有 a = false

xa+n 代表 a = true

xb 代表 b = false

我们就建一条边由 xa+n 指向 xb

这条边就代表选择xa+n 就必须选 xb

无解的情况:

某一个变量的 false 能走到 true,从 true 也能走到 false,就说明无解。

为什么一个变量的 false(true) 能走到一个变量的 true(false) 不是无解的情况呢?

我们考虑边的意义:

选了这个变量的 false 就必须选这个变量的 true

那就选这个变量的 true不就好了!

这也是我们如何找出解的方法:

找出解

我们把每个点的 false 都 dfs 一次,

如果找不到这个点的 true,那就代表这个点可以选 false,

若找到了这个点的 true,则再在 true 上dfs一次,

如果 dfs 找不到 false,则代表这个点选true,

如果也 dfs 到了 false,那就证明无解。

这样的复杂度是O(n2) 显然不能过

那怎么办呢?

我们考虑

tarjan缩点

某一个变量的 false 能走到 true,从 true 也能走到 false,就说明无解。

这就说明一个变量的 false 与 true 在一个强连通分量里面

tarjan 可以很好解决这个问题

for(int i = 1;i <= n; ++i){
	if(c[i] == c[i + n]){
		return 0;
	}
}

那怎么找出解呢?

我们考虑

情况1:当一个点的 false 与 true 不会互相到达(指向),那就可以随便取

情况2:当一个点的 false 可以到达(指向) true,那就只能取 true

情况3:当一个点的 true 可以到达(指向) false,那就只能取 false

相互可以到达(就上面说的情况)就无解。

我们首先判断出来这有没有解,如果有解,那么情况二和情况三不可能都满足

我们现在所需要看的就是到底满足哪一个情况?

首先因为没有false和true是同一个强联通分量,所以

当一个点的 false 可以到达(指向) true,那么这个点的 false 在tarjan(dfs)里面必定被先找到,c[false] 也就比 c[true] 更大

当一个点的 true 可以到达(指向) false,那么这个点的 true 在tarjan(dfs)里面必定被先找到,c[true] 也就比 c[false] 更大

当两个点没关系的时候,可以随便取

for(int i = 1;i <= n; ++i){
	if(c[i] > c[i + n]) printf("1 ");
	else printf("0 ");
}
posted @   He_Zi  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示