【模板】2-SAT问题
问题简述
有 \(n\) 个变量,每个变量可赋为 \(1\) 或 \(0\)
必须满足一些限制条件,如“ \(a\) 为1 或 \(b\) 为0 ” “ \(a\) 为0 且 \(b\) 为1” …
判断是否有一种赋值方法满足所有限制条件,并构造答案。
做法
首先拆点,把每个变量 \(i\) 拆成 \(i\) 选1 和 \(i\) 选0 两个点,在这两个点中选出一个
现在我们在 \(2n\) 个点中选出了 \(n\) 个点,相当于选择了一种赋值方案
换句话说,每种赋值方案就是在 每对 \(i\) 选1 和 \(i\) 选0 中选一个点
考虑所有限制条件,有两种类型。
第一种是 “ \(x_i=k_i\) 且 \(x_j=k_j\) ”
我们可以连一些有向边 \((u,v)\),表示如果选了 \(u\) ,就一定要选 \(v\)
那针对这种情况,则要连 \((x_i选k_i, x_j选k_j)\)
但这样还不够!
回忆一下“逆否命题”,我们还需连 \((x_j不选k_j,x_i不选k_i)\) 才可保证限制满足。
第二种是 “ \(x_i=k_i\) 或 \(x_j=k_j\) ”
连边 \((x_i不选k_i, x_j选k_j)\) 和 \((x_j不选k_j,x_i选k_i)\)
这样下来,我们发现连的所有边是对称的!(真命题&逆否命题嘛)
接下来,我们对这个有向图跑强连通分量缩点。
对每个强连通分量,要么都选,要么都不选。
还记得如何选赋值方案吗?
每对\(i\) 选1 和 \(i\) 选0 中只能选1个,那么判断一下,如果这两个点在同一个强连通分量中,则无解。
如果不在,选拓扑排序中拓扑序靠后的那个点,(也就是 \(tarjan\) 中编号较小的那个点),可以保证这样选出的点是一组合理的赋值方案。
代码
洛谷模板题 \(P4782\)
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 2000005;
struct node{
int v;
node *nxt;
}pool[N],*h[N];
int cnt;
void addedge(int u,int v){
node *p=&pool[++cnt];
p->v=v;p->nxt=h[u];h[u]=p;
}
int n,m;
int tot;
int dfn[N],low[N],scc,belong[N];
int st[N],top,vis[N];
void tarjan(int u){
int v;
dfn[u]=low[u]=++tot;
vis[u]=1;
st[top++]=u;
for(node *p=h[u];p;p=p->nxt)
if(!dfn[v=p->v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v]) low[u]=min(low[u],dfn[v]);
if(low[u]==dfn[u]){
scc++;
while(1){
belong[st[--top]]=scc;
vis[st[top]]=0;
if(st[top]==u) break;
}
}
}
int main()
{
int a,b,c,d;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d%d%d",&a,&b,&c,&d);
addedge(a+(1-b)*n,c+d*n);
addedge(c+(1-d)*n,a+b*n);
}
for(int i=1;i<=2*n;i++)
if(!dfn[i]) tarjan(i);
int flag=0;
for(int i=1;i<=n;i++)
if(belong[i]==belong[i+n]) flag=1;
if(flag) { printf("IMPOSSIBLE\n"); return 0; }
printf("POSSIBLE\n%d",belong[1]>belong[n+1]);
for(int i=2;i<=n;i++) printf(" %d",belong[i]>belong[n+i]);
return 0;
}
【模板】2-SAT问题的更多相关文章
- 2 - sat 模板(自用)
2-sat一个变量两种状态符合条件的状态建边找强连通,两两成立1 - n 为第一状态(n + 1) - (n + n) 为第二状态 例题模板 链接一 POJ 3207 Ikki's Story IV ...
- TwoSAT算法模板
该模板来自大白书 [解释] 给多个语句,每个语句为“ Xi为真(假) 或者 Xj为真(假)” 每个变量和拆成两个点 2*i为假, 2*i+1为真 “Xi为真 或 Xj为真” 等价于 “Xi为假 –& ...
- C++ 模板基础
我们学习使用C++,肯定都要了解模板这个概念.就我自己的理解,模板其实就是为复用而生,模板就是实现代码复用机制的一种工具,它可以实现类型参数化,即把类型定义为参数:进而实现了真正的代码可重用性.模版可 ...
- (模板)poj2947(高斯消元法解同余方程组)
题目链接:https://vjudge.net/problem/POJ-2947 题意:转换题意后就是已知m个同余方程,求n个变量. 思路: 值得学习的是这个模板里消元用到lcm的那一块.注意题目输出 ...
- 虚拟化技术之kvm镜像模板制作工具virt-sysprep
virt-sysprep这个工具来自libguest-tools这个工具包,它能够把kvm虚拟机对应的磁盘文件做成一个模板,后续我们启动虚拟机就可以基于这个镜像模板启动:什么是镜像模板呢?所谓模板就是 ...
- Jade模板引擎让你飞
写在前面:现在jade改名成pug了 一.安装 npm install jade 二.基本使用 1.简单使用 p hello jade! 渲染后: <p>hello jade!</p ...
- ABP入门系列(2)——通过模板创建MAP版本项目
一.从官网创建模板项目 进入官网下载模板项目 依次按下图选择: 输入验证码开始下载 下载提示: 二.启动项目 使用VS2015打开项目,还原Nuget包: 设置以Web结尾的项目,设置为启动项目: 打 ...
- CMS模板应用调研问卷
截止目前,已经有数十家网站与我们合作,进行了MIP化改造,在搜索结果页也能看到"闪电标"的出现.除了改造方面的问题,MIP项目组被问到最多的就是:我用了wordpress,我用了织 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- 【原创分享·微信支付】C# MVC 微信支付之微信模板消息推送
微信支付之微信模板消息推送 今天我要跟大家分享的是“模板消息”的推送,这玩意呢,你说用途嘛,那还是真真的牛逼呐.原因在哪?就是因为它是依赖微信生存的呀,所以他能不 ...
随机推荐
- 51nod 1307绳子和重物
1307 绳子与重物 题目来源: Codility 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 收藏 关注 有N条绳子编号 0 至 N - 1,每条绳子后 ...
- Linux 标准 C 类型的使用
尽管大部分程序员习惯自由使用标准类型, 如 int 和 long, 编写设备驱动需要一些小心 来避免类型冲突和模糊的 bug. 这个问题是你不能使用标准类型, 当你需要"一个 2-字节 填充 ...
- JS只执行一次
1.闭包实现. <script> window.onload = function () { function once(fn) { var result; return function ...
- jQuery 工具类函数-检测两个节点的包含关系
调用名为$.contains的工具函数,能检测在一个DOM节点中是否包含另外一个DOM节点,如果包含,返回true,否则,返回false值,调用格式为: $.contains (container, ...
- Vue学习笔记-基本语法
插值文本(输出文本):{{ }}或v-textHtml(输出Html):v-html 监听属性常用于表单输入时要进行的动作watch : { dataValue:function(val) { }} ...
- Java 工程师应该掌握的知识
以 Java 工程师应该掌握的知识为例,按重要程度排出六个梯度: 第一梯度:计算机组成原理.数据结构和算法.网络通信原理.操作系统原理. 第二梯度:Java 基础.JVM 内存模型和 GC 算法.JV ...
- Centos中Qt编译问题(/usr/bin/ld: 找不到 -lpulse-mainloop-glib,/usr/bin/ld: 找不到 -lpulse...)
Linux下QT编写一个与视频播放的程序,出现/usr/bin/ld: 找不到 -lpulse-mainloop-glib,/usr/bin/ld: 找不到 -lpulse 解决办法: 首先find ...
- mac 访达修改所有文件夹默认排序方式
先说个误区,下图只能改变当前目录的排序方式 修改所有目录的排序方式需要在顶部的“显示” 中修改
- Mybatis入门案例中设计模式的简单分析
Talk is cheap, show me the code! public class TestMybatis { public static void main(String[] args) t ...
- linux大盘格式化分区
Linux 实例的磁盘管理 对于 Linux 系统上的大磁盘,也要采用 GPT 分区格式, 也可以不分区, 把磁盘当成一个整体设备使用. 在 Linux 上一般采用 XFS 或者 EXT4 来做大盘的 ...