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

题目描述
有n个布尔变量 x 1 x   x n x_1x~x_n x1x xn,另有m个需要满足的条件,每个条件的形式都是“ x i x_i xi t r u e / f a l s e true/false true/false x j x_j xj t r u e / f a l s e true/false true/false”。比如“ x 1 x_1 x1为真或 x 3 x_3 x3为假”、“ x 7 x_7 x7为假或 x 2 x_2 x2为假
为假或 x 2 x_2 x2为假”。2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。
输入格式
第一行两个整数n和m,意义如体面所述。
接下来m行每行4个整数 i a j b i a j b iajb,表示“ x i x_i xi a a a x j x_j xj b b b”(a,b∈{0,1})
输出格式
如无解,输出“IMPOSSIBLE”(不带引号); 否则输出"POSSIBLE"(不带引号),下 一行n个整数 x 1   x n , x ∈ 0 , 1 x_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; = 1 e 6 1&lt;=n,m&lt;=1e^6 1<=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]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值