zoukankan      html  css  js  c++  java
  • P4782 【模板】2-SAT 问题

    (color{#0066ff}{ 题目描述 })

    (n)个布尔变量(x_1)~(x_n),另有(m)个需要满足的条件,每个条件的形式都是“(x_i)(true/false)(x_j)(true/false)”。比如“(x_1)为真或(x_3)为假”、“(x_7)为假或(x_2)为假”。2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。

    $color{#0066ff}{ 输入格式 } $

    第一行两个整数n和m,意义如体面所述。

    接下来m行每行4个整数 i a j b,表示“(x_i)为a或(x_j)为b”(a,b∈{0,1})

    (color{#0066ff}{输出格式})

    如无解,输出“IMPOSSIBLE”(不带引号); 否则输出"POSSIBLE"(不带引号),下 一行n个整数(x_1)~(x_n)(x_i)∈{0,1}),表示构造出的解。

    (color{#0066ff}{输入样例})

    3 1
    1 1 3 0
    

    (color{#0066ff}{输出样例})

    POSSIBLE
    0 0 0
    

    (color{#0066ff}{数据范围与提示})

    有spj

    (n ,mleq 10^6)

    (color{#0066ff}{ 题解 })

    2——SAT板子题

    建图

    每个变量x拆成x和x+n

    x代表x取true的状态,x+n代表x取false的状态

    图中有向边的含义:(x->y)有状态x, 必有状态y

    比如(x|y=1)也就是说x和y至少有一个是1

    就这样连(x+n->y, y+n->x)

    x为0时,要保证式子成立,y必须为1

    这样就能建好图了

    考虑一个环,一个知道其中一个点的状态,其它的都出来了,所以锁点一下

    当x和x+n在一个强联通分量里就不行了,冲突了,无解

    现在考虑怎么输出方案

    当 (x) 所在的强连通分量的拓扑序在 (x+n) 所在的强连通分量的拓扑序之后取 (x) 为真即可

    在tarjan的过程中,实际上我们强联通分量的编号就是倒着的拓扑序qwq

    Code

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    const int maxn = 2e6 + 100;
    struct node {
    	int to;
    	node *nxt;
    	node(int to = 0, node *nxt = NULL): to(to), nxt(nxt) {}
    	void *operator new(size_t) {
    		static node *S = NULL, *T = NULL;
    		return (S == T) && (T = (S = new node[1024]) + 1024), S++;
    	}
    };
    node *head[maxn];
    bool ins[maxn];
    int st[maxn], top, bel[maxn], cnt, n, m, tot;
    int dfn[maxn], low[maxn];
    void add(int from, int to) {
    	head[from] = new node(to, head[from]);
    }
    void tarjan(int x) {
    	dfn[x] = low[x] = ++tot;
    	ins[st[++top] = x] = true;
    	for(node *i = head[x]; i; i = i->nxt) {
    		if(!dfn[i->to]) {
    			tarjan(i->to);
    			low[x] = std::min(low[x], low[i->to]);
    		}
    		else if(ins[i->to]) low[x] = std::min(low[x], dfn[i->to]);
    	}
    	if(dfn[x] == low[x]) {
    		cnt++;
    		do {
    			bel[st[top]] = cnt;
    			ins[st[top]] = false;
    			top--;
    		}while(st[top + 1] != x);
    	}
    }
    bool judge() {
    	for(int i = 1; i <= n; i++) printf("i = %d, bel = [%d,%d]
    ", i, bel[i], bel[i + n]);
    	for(int i = 1; i <= n; i++) if(bel[i] == bel[i + n]) return true;
    	return false;
    }
    int main() {
    	n = in(), m = in();
    	int x, y, xx, yy;
    	for(int i = 1; i <= m; i++) {
    		x = in(), xx = in(), y = in(), yy = in();
    		if(xx && yy) add(x + n, y), add(y + n, x);
    		if(xx && !yy) add(x + n, y + n), add(y, x);
    		if(!xx && yy) add(x, y), add(y + n, x + n);
    		if(!xx && !yy) add(x, y + n), add(y, x + n);
    	}
    	for(int i = 1; i <= n << 1; i++) if(!dfn[i]) tarjan(i);
    	if(judge())	printf("IMPOSSIBLE
    ");
    	else {
    		printf("POSSIBLE
    ");
    		for(int i = 1; i <= n; i++) 
    			printf("%d%c", bel[i] < bel[i + n]? 1 : 0, i == n? '
    ' : ' ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    JS函数的定义与调用方法
    一次完整的浏览器请求流程
    【前端安全】JavaScript防http劫持与XSS
    深入理解display属性
    前端开发人员需要了解的CSS原理
    第 10 章 文件系统及实现
    第 9 章 虚拟内存管理
    第 8 章 内存管理策略
    第 7 章 死锁
    第 6 章 同步
  • 原文地址:https://www.cnblogs.com/olinr/p/10335522.html
Copyright © 2011-2022 走看看