闲谈2-sat问题
问题简介
在计算机科学中,布尔可满足性问题(有时称为命题可满足性问题,缩写为SATISFIABILITY或SAT)是确定是否存在满足给定布尔公式的解释的问题。换句话说,它询问给定布尔公式的变量是否可以一致地用值TRUE或FALSE替换,公式计算结果为TRUE。如果是这种情况,公式称为可满足。另一方面,如果不存在这样的赋值,则对于所有可能的变量赋值,公式表示的函数为FALSE,并且公式不可满足。例如,公式“a AND NOT b”是可以满足的,因为可以找到值a = TRUE且b = FALSE,这使得(a AND NOT b)= TRUE。相反,“a AND NOT a”是不可满足的。——百度百科
在每个限制中牵扯到的最多的元素假设是\(k\),我们就称为\(k-sat\)问题。可以证明当\(k \ge 3\)时为\(np\)完全问题。下面只讨论\(k=2\)的情况。
引入
从一个最简单的\(2-sat\)问题开始今天的讨论
有n对夫妻被邀请参加一个聚会,因为场地的问题,每对夫妻中只有1人可以列席。在2n 个人中,某些人之间有着很大的矛盾(当然夫妻之间是没有矛盾的),有矛盾的2个人是不会同时出现在聚会上的。有没有可能会有n 个人同时列席?——hdu3062
对于每对夫妻,我们可以将丈夫去看作\(1\),妻子去看作\(0\)。要求给每对夫妻确定一个值,使得满足这\(m\)个限制。
这就是最简单的\(2-sat\)模型。
构图
先观察这些限制,假设A中的丈夫不能和B中的妻子一起去(???)。那么也就是说,A中的丈夫只能和B中的丈夫一起去。也就是说,如果A中的丈夫去,那么B中的丈夫也必须去。同理,如果B中的妻子去,那么A中的妻子也必须去。
我们就从A中的丈夫向B中的丈夫连一条边,从B中的妻子向A中的妻子连一条边,表示这些"必须"的条件。
显然我们就可以得到这样一个结论:如果一个点被选了,那么这个点所能到达的所有点也必须被选择。如果一个点没选,那么所有可以到达这个点的点都不能选。出现矛盾当且仅当某对夫妻的丈夫和妻子都必须去。
算法
暴力解法
我们枚举每一个人选或者不选,然后去查看是否会出现矛盾。
如果一对夫妻中两个人不论选择谁都会出现矛盾。那么问题必定无解。
优化
继续推一些结论。
对于同一个强连通分量里的点,如果选择其中一个,那么这个强连通分量中的点必须全部选择。这样我们可以先\(tarjan\)缩点。如果一对夫妻出现在了同一个强连通分量里面肯定无解。否则一定有解。
找可行解可以先拓扑排序一下,然后自底向上的顺序推导。
证明
观察我们的构图方式可以发现构出来的图有对称性。
啥是对称性??
如图。我们观察其中的一组点,比如\(c\)
发现可以到达\(c_0\)的点是\(a_0\),\(c_0\)可以到达的点是\(d_0\),而可以到达\(c_1\)的点是\(d_1\),\(c_1\)可以到达的点是\(a_1\)。刚好对称。也就是说我们只要保证\(c_0\)可以到达的不会矛盾,那么就可以保证可以到达\(c_1\)的点不会矛盾。我们如果选择了\(c_0\),那么就一定选择\(d_0\),这时把\(c_1\)和\(d_1\)都删去。按照这种思路,我们每次找到一个未确定的点\(x\),使得\(x\)到达的点中没有\(x'\)(即x的对立点)。
这样我们一定可以找到一组解。而无解的情况也就是找不到这种点的时候。即一对点存在于同一个强连通分量中。
然后思考求解的过程,因为要使得“\(x\)到达的点中没有\(x'\)(即x的对立点)。”
所以可以拓扑排序。然后就自底向上的找答案。
有一种更加简单的找可行解的方法。
注意到\(Tarjan\)算法的本质是一次\(dfs\),他在回溯时会优先取出有向图"底部"的\(scc\)进行标记。故\(Tarjan\)算法得到的\(scc\)编号本身就已经满足缩点后的有向无环图中"自底向上"的拓扑序。——《算法竞赛进阶指南》
得出结论:直接比较缩点之后编号的大小就可以得出答案,较小的为1,较大的为0。
资料
我讲的不好??
没关系,再看些资料吧。
https://blog.csdn.net/qq_24451605/article/details/47126143
由对称性解2-sat问题
代码
/*
* @Author: wxyww
* @Date: 2019-04-28 18:50:21
* @Last Modified time: 2019-04-28 19:59:02
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 2010;
ll read() {
ll x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
struct node{
int v,nxt;
}e[1000000];
int n,m,ejs,head[N];
void add(int u,int v) {
e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;
}
int vis[N],tot,dfn[N],low[N],sta[N],coljs,top,col[N];
void tarjan(int u) {
dfn[u] = low[u] = ++tot;
sta[++top] = u;vis[u] = 1;
for(int i = head[u];i;i = e[i].nxt) {
int v = e[i].v;
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(vis[v]) low[u] = min(low[u],low[v]);
}
if(low[u] == dfn[u]) {
++coljs;
do {
int x = sta[top--];
col[x] = coljs;
vis[x] = 0;
}while(sta[top + 1] != u);
}
}
int main() {
while(~scanf("%d%d",&n,&m)) {
memset(head,0,sizeof(head));
ejs = 0;
coljs = 0;
memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));
tot = 0;top = 0;
for(int i = 1;i <= m;++i) {
int x = read() + 1,y = read() + 1;
int c1 = read(),c2 = read();
if(c1) {
if(c2) add(x + n, y),add(y + n,x);
else add(x + n,y + n),add(y,x);
}
else {
if(c2) add(x, y),add(y + n,x + n);
else add(x,y + n),add(y,x + n);
}
}
for(int i = 1;i <= n + n;++i) if(!dfn[i]) tarjan(i);
int bz = 0;
for(int i = 1;i <= n;++i) {
if(col[i] == col[i + n]) {
bz = 1;break;
}
}
puts(bz ? "NO" : "YES");
}
return 0;
}
闲谈2-sat问题的更多相关文章
- 多边形碰撞 -- SAT方法
检测凸多边形碰撞的一种简单的方法是SAT(Separating Axis Theorem),即分离轴定理. 原理:将多边形投影到一条向量上,看这两个多边形的投影是否重叠.如果不重叠,则认为这两个多边形 ...
- POJ 3678 Katu Puzzle(2 - SAT) - from lanshui_Yang
Description Katu Puzzle is presented as a directed graph G(V, E) with each edge e(a, b) labeled by a ...
- Node闲谈之Buffer
在刚接触Nodejs的时候,有些概念总让学前端的我感到困惑(虽然大学的时候也是在搞后端,世界上最好的语言,you know).我可以很快理解File System,Path等带有明显功能的模块,却一下 ...
- Map Labeler POJ - 2296(2 - sat 具体关系建边)
题意: 给出n个点 让求这n个点所能建成的正方形的最大边长,要求不覆盖,且这n个点在正方形上或下边的中点位置 解析: 当然是二分,但建图就有点还行..比较难想..行吧...我太垃圾... 2 - s ...
- 学习笔记(two sat)
关于two sat算法 两篇很好的论文由对称性解2-SAT问题(伍昱), 赵爽 2-sat解法浅析(pdf). 一些题目的题解 poj 3207 poj 3678 poj 3683 poj 3648 ...
- 转悠望南山 Python闲谈(二)聊聊最小二乘法以及leastsq函数
1 最小二乘法概述 自从开始做毕设以来,发现自己无时无刻不在接触最小二乘法.从求解线性透视图中的消失点,m元n次函数的拟合,包括后来学到的神经网络,其思想归根结底全都是最小二乘法. 1-1 “多线 ...
- LA 3211 飞机调度(2—SAT)
https://vjudge.net/problem/UVALive-3211 题意: 有n架飞机需要着陆,每架飞机都可以选择“早着陆”和“晚着陆”两种方式之一,且必须选择一种,第i架飞机的早着陆时间 ...
- c# 闲谈异常处理
今天在阅读 .net 源码时发现微软对所有使用枚举类型的地方对枚举值进行了检测,在检测不通过时抛出了异常. , )) { throw new InvalidEnumArgumentException( ...
- HIT 1917 2—SAT
题目大意:一国有n个党派,每个党派在议会中都有2个代表, 现要组建和平委员会,要从每个党派在议会的代表中选出1人,一共n人组成和平委员会. 已知有一些代表之间存在仇恨,也就是说他们不能同时被选为和平委 ...
随机推荐
- Java体系学习书籍推荐
以下所有资料均可在:Java知识分享网下载. 大家有推荐的书可以在下方留言! 开源代码GitHub仓库总结 计算机基础 计算机科学导论 --(如果不是计算机科班的,应先看看计算机基础,了解一些基本概 ...
- javascript 实现数据结构 - 栈
栈是一种遵从后进先出(LIFO)原则的有序集合.新添加的或待删除的元素都保存在栈的同一端,称作栈顶,另一端就叫栈底.在栈里,新元素都靠近栈顶,旧元素都接近栈底.栈就好像是一个底部密封的盒子,我们往里面 ...
- Spring之旅第三篇-Spring配置详解
上一篇学习了IOC的概念并初步分析了实现原理,这篇主要学习Spring的配置,话不多说,让我们开始! 一.Bean元素配置 1.1 基本配置 看一个最基本的bean配置 <bean name=& ...
- ES 09 - 定制Elasticsearch的分词器 (自定义分词策略)
目录 1 索引的分析 1.1 分析器的组成 1.2 倒排索引的核心原理-normalization 2 ES的默认分词器 3 修改分词器 4 定制分词器 4.1 向索引中添加自定义的分词器 4.2 测 ...
- springboot~Integer和int如何选择,Integer的意义何在
今天说一下自己在项目中遇到的问题,然后总结一下Integer引用类型和int值类型 关于默认值 Integer默认为null int默认为0 为什么把数据实体设计成Integer或者不是int 大叔认 ...
- DotNetCore跨平台~关于appsettings.json里各种配置项的读取
回到目录 对于dotnet Core来说,依赖注入的集成无疑是最大的亮点,它主要用在服务注册与注入和配置文件注册与注入上面,我们一般会在程序入口先注册服务或者文件,然后在需要的地方使用注入即可,下面主 ...
- LindDotNetCore~职责链模式的应用
回到目录 职责链模式 它是一种设计模块,主要将操作流程与具体操作解耦,让每个操作都可以设置自己的操作流程,这对于工作流应用是一个不错的选择! 下面是官方标准的定义:责任链模式是一种设计模式.在责任链模 ...
- 深入解析ThreadLocal 详解、实现原理、使用场景方法以及内存泄漏防范 多线程中篇(十七)
简介 从名称看,ThreadLocal 也就是thread和local的组合,也就是一个thread有一个local的变量副本 ThreadLocal提供了线程的本地副本,也就是说每个线程将会拥有一个 ...
- AppBoxFuture(五): 分布式文件存储-Store Everything
本来本篇是想介绍前端组件化开发用户界面,发现框架还未实现文件存储,原本计划是后续设计开发的,索性把计划提前,所以本篇将介绍基于Raft实现分布式的文件存储引擎. 一. 实现思路 既然是分布式存 ...
- ABAP案例:灵活读取SAP各表的数据
案例说明 RFC读取表中数据. Import 参数名称 Type spec. 参考打印 FIELDS_NAME1 TYPE CHAR25 TABLE_NAME1 TYPE CHAR25 WHE ...