洛谷-4782 【模板】2-SAT 问题

本文探讨了2-SAT问题的解决方法,这是一种特殊的布尔可满足性问题,通过使用深度优先搜索和Tarjan算法来寻找强连通分量,从而确定是否存在满足所有条件的变量赋值方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述
有n个布尔变量x1x xnx_1x~x_nx1x xn,另有m个需要满足的条件,每个条件的形式都是“xix_ixitrue/falsetrue/falsetrue/falsexjx_jxjtrue/falsetrue/falsetrue/false”。比如“x1x_1x1为真或x3x_3x3为假”、“x7x_7x7为假或x2x_2x2为假
为假或x2x_2x2为假”。2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。
输入格式
第一行两个整数n和m,意义如体面所述。
接下来m行每行4个整数 iajbi a j biajb,表示“xix_ixiaaaxjx_jxjbbb”(a,b∈{0,1})
输出格式
如无解,输出“IMPOSSIBLE”(不带引号); 否则输出"POSSIBLE"(不带引号),下 一行n个整数x1 xn,x∈0,1x_1~x_n,x∈{0,1}x1 xn,x0,1,表示构造出的解。

输入输出样例
输入 #1
3 1
1 1 3 0

输出 #1
POSSIBLE
0 0 0

说明/提示
1&lt;=n,m&lt;=1e61&lt;=n,m&lt;=1e^61<=n,m<=1e6

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <stack>
const int N = 2e6 + 62;
struct edge{
    int to,next;
}e[N << 1];
static int head[N], cnt;
inline void addedge(int x, int y){ e[++cnt] = (edge){y, head[x]}, head[x] = cnt; }
static int dfn[N], low[N], vis[N], col[N], scnt, idx;
std::stack<int> st;
void dfs(int x){
    dfn[x] = low[x] = ++idx, vis[x] = 1;
    st.push(x);
    for(int i = head[x]; i; i = e[i].next){
        int nx = e[i].to;
        if(!dfn[nx]){
            dfs(nx);
            low[x] = std::min(low[x], low[nx]);
        }else if (vis[nx]) low[x] = std::min(low[x], dfn[nx]);
    }
	if(dfn[x] == low[x]){
		for (scnt++; !st.empty();){
        	int _ = st.top();
        	st.pop(), vis[_] = 0, col[_] = scnt;
            if (_ == x) break;
        }
    }
}
int n, m, x, a, y, b;
int main(){
    register int i;
    for(scanf("%d%d", &n, &m);m--;){
        scanf("%d%d%d%d", &x, &a, &y, &b);
        addedge(x + !a * n, y + b * n);
        addedge(y + !b * n, x + a * n);
    }
    for(i = 1; i <= 2 * n; i++) if(!dfn[i]) dfs(i);
    for(i = 1; i <= n; i++) if(col[i] == col[n + i]) return puts("IMPOSSIBLE"), 0;
    puts("POSSIBLE");
    for (i = 1; i <= n; i++) printf("%d ", col[i] > col[n + i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值