首页 > 其他分享 >「学习笔记」2-SAT问题

「学习笔记」2-SAT问题

时间:2023-04-23 18:12:57浏览次数:59  
标签:连边 false 笔记 学习 集合 true 我们 SAT

SAT 是适定性 \(\text{(Satisfiability)}\) 问题的简称。一般形式为 k - 适定性问题,简称 k-SAT。而当 \(k>2\) 时该问题为 NP 完全的。所以我们只研究 \(k=2\) 的情况。
2-SAT,简单的说就是给出 \(n\) 个集合,每个集合有两个元素,已知若干个 \(<a,b>\),表示 \(a\) 与 \(b\) 矛盾(其中 \(a\) 与 \(b\) 属于不同的集合)。然后从每个集合选择一个元素,判断能否一共选 \(n\) 个两两不矛盾的元素。显然可能有多种选择方案,一般题中只需要求出一种即可。

建图

我们将 \(n\) 个集合拆成两个点,分别代表着 truefalse.
a || b == true 时,我们可以得知:
a == false 时,b = true
b == false 时,a = true;
这两个关系存在因果关系;
a == true 时,我们不能得知 b = true 还是 b = false,这两者之间不存在因果关系,b == true 同理。
因此,我们将 \(a_0\) 向 \(b_1\) 连边,将 \(b_0\) 向 \(a_1\) 连边。

含义:
a == false 时,b = true
b == false 时,a = true

a && b == false 时,我们可以得知:
a == true 时,b = false;
b == true 时,a = false;
我们将 \(a_1\) 向 \(b_0\) 连边,将 \(b_1\) 向 \(a_0\) 连边。

含义:
a == true 时,b = false;
b == true 时,a = false

a && b == true 时,我们发现,a == trueb == true,除了这种情况不会再有其他情况了,即 \(a\) 的值一定为 true,\(b\) 的值一定为 true
这种情况下,我们将 \(a_0\) 向 \(a_1\) 连边,\(b_0\) 向 \(b_1\) 连边。

含义:
a == false 时,a = true;(即 \(a\) 一定不为 false
b == false 时,b = true。(即 \(b\) 一定不为 true)

判断是否有解

如果 \(a_0\) 可以到达 \(a_1\),说明 \(a\) 一定为 true
如果 \(a_1\) 可以到达 \(a_0\),说明 \(a\) 一定为 false
判断是否有解即在一种情况中 \(a\) 都有唯一确定的值,要么为 true,要么为 false,倘若在同一种情况中,\(a_0\) 可以到达 \(a_1\), \(a_1\) 可以到达 \(a_0\),则无法确定 \(a\) 的值,此情况下无解,即 \(a_0\) 与 \(a_1\) 在同一个强连通分量里。
用 tarjan 算法来找强连通分量即可。

题目

P4782 【模板】2-SAT 问题

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1e6 + 5;

int n, m, tim, scc;
vector<int> son[N << 1], sta;
int dfn[N << 1], low[N << 1], lt[N << 1];

void tarjan(int u) {
	dfn[u] = low[u] = ++ tim;
	sta.push_back(u);
	for (int v : son[u]) {
		if (!dfn[v]) {
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if (!lt[v]) {
			low[u] = min(low[u], dfn[v]);
		}
	}
	if (dfn[u] == low[u]) {
		lt[u] = ++ scc;
		while (sta.back() != u) {
			lt[sta.back()] = scc;
			sta.pop_back();
		}
		sta.pop_back();
	}
}

int main() {
	scanf("%d%d", &n, &m);
	while (m --) {
		int xi, i, xj, j;
		scanf("%d%d%d%d", &xi, &i, &xj, &j);
		son[xi + n * (i & 1)].push_back(xj + (j ^ 1) * n);
		son[xj + n * (j & 1)].push_back(xi + (i ^ 1) * n);
	}
	for (int i = 1; i <= (n << 1); ++ i) {
		if (!dfn[i]) {
			tarjan(i);
		}
	}
	for (int i = 1; i <= n; ++ i) {
		if (lt[i] == lt[i + n]) {
			puts("IMPOSSIBLE");
			return 0;
		}
	}
	puts("POSSIBLE");
	for (int i = 1; i <= n; ++ i) {
		printf("%d%c", (lt[i] < lt[i + n]), " \n"[i == n]);
	}
	return 0;
}

标签:连边,false,笔记,学习,集合,true,我们,SAT
From: https://www.cnblogs.com/yifan0305/p/17346853.html

相关文章

  • RxDart框架学习
    一、RxDart是什么?RxDart是一个响应式编程框架,是基于ReactiveX的响应式函数编程库,ReactiveX是一个强大的库,通过使用可观察的序列来编写异步的程序。它突破了语言以及平台的限制,使我们在写异步程序的时候更简洁。ReactiveX开发过多个语言下的响应式框架,比较有名的就是RxJava、R......
  • 《Redis设计与实现》读书笔记
    《Redis设计与实现》读书笔记简单动态字符串SDS的定义结构:buf数组:用于保存字符串len属性:记录SDS中保存字符串的长度free属性:记录buf中未使用字节数量遵循C字符串以空字符串结尾的惯例,保存空字符串的字节不计入长度SDS与C字符串的区别常数复杂度获取字符串长度因为SDS中......
  • 自学Vue基础笔记
    ......
  • Markdowm学习
    #Markdowm学习标题##二级标题###三级标题#字体**Hello,world!***Hello,world****Hello,worid!***~~Hello,world!~~#引用>##分割线---##图片![截图](E:\新建文件夹(2)\屏幕截图2022-11-12165730.png)![图片]()##超链接[点击跳转](http://m.jrj.com.cn/......
  • Unity___QFramework笔记
    引入Event引入事件监听。使用方法先定义一个事件类//定义数据变更事件publicstructCountChangeEvent//++{}//执行事件this.SendEvent<CountChangeEvent>();//++//注册事件this.RegisterEvent<CountChangeEvent>(e......
  • 安装centos79的笔记
    一、安装下载centos79最终全集版的iso文件:https://mirrors.tuna.tsinghua.edu.cn/centos/7.9.2009/isos/x86_64/一般建议下载那个CentOS-7-x86_64-Everything-2207-02.iso,一代经典的centos7,出到的最后一个版本。这里进行的是在vmwareworkstation16.1中安装,2C4G40G的简朴配置......
  • Vue的学习笔记(下篇)
    一、什么是Vue.js?Vue是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue也完全能够为复杂的单页......
  • Vue的学习笔记(中篇)
    一、什么是Vue.js?Vue是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue也完全能够为复杂的单页......
  • 「学习笔记」重修 FHQ-treap
    无旋treap的操作方式使得它天生支持维护序列、可持久化等特性。无旋treap又称分裂合并treap。它仅有两种核心操作,即为分裂与合并。通过这两种操作,在很多情况下可以比旋转treap更方便的实现别的操作。变量与宏定义#definelsch[u][0]#definersch[u][1]intcnt,r......
  • rpc学习--替换rpc序列化协议为json
    rpc概念:RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。示例代码:packagemainimport("encoding/json""log""net"......