前置知识

强连通分量

k-SAT问题

k-SAT问题中的SAT意思就是(stability),也就是适应性问题。本意是给出n个变量,每一个变量有k个状态,并且也给出一些约束条件,要求你求出是否存在每一个变量的取值方案(状态分配方案)。

很可惜,k-SAT(k>2)已经被证明是NP完全的问题了,也就是说我们无法用一些多项式时间复杂度的算法来解决这个问题,但是我们可以发现。当k<=2的时候,我们可以用一些多项式时间复杂度的算法来解决这个问题。

2-SAT问题

先来一道模板题:

Luogu P4782

下面是对2-sat问题的一个例子

假如你是一个厨师,现在要给两个人做菜,每个人的口味都不同,而你至少要满足每个人的一个口味。这些人会提一些要求,比方说:

A:

  • 我不喜欢吃辣椒(-a)
  • 我喜欢吃肥肉有(b)

B:

  • 我不喜欢吃辣椒(-a)
  • 我不喜欢吃肥肉(-b)

那么我们可以用这种形式来简化表示约束条件:

A: -a or B: -a

A: b or B -b

对于每一个\(x_i\) or \(x_j\)的约束条件,我们可以将其变化成:

若\(x_i\)为假则\(x_j\)为真

若\(x_i\)为真则\(x_j\)为假

就比如说 A:-a or B:-b 可以变成

若 A:-a为假,则B: -b为真

若 B:-b为假,则A:-a为真

对上面的例子进行缩写,可以得到:

若A为a,则B为-b

若B为b,则A为-a

(因为-a为假的话证明肯定就是a了,反之亦然,同时也适用于b的情况)

于是,对于每一种约束条件的格式,我们都可以像上面这样分析,然后发现一些传递的关系:

我们把每一个变量抽象成图上的两个点,两个点分别代表了原来一个变量的两个不同的状态。也就是说变成a 和 -a (就是a真和a假)。

我们可以针对每一种约束条件把相对应的关系传递用有向边连接起来,表示从A的某一个状态可以推测出B的值(或者是b的某一个状态可以推得a的状态),也就是说这会形成一些链,在链上的每一个变量的值都是确定了的。但是根据数据的不同,实际上会出现强连通分量。并且如果一个强连通分量中包括某一个和原来a取值相反的-a的取值,则代表其矛盾,也就是说无解

我们这里使用tarjan求SCC(强连通分量)的算法来检测环的出现与否。

那么当问题有解的时候,我们该如何显示每一个变量的值呢?难道我们还需要对原图进行拓扑+染色吗?实际上我们并不需要这么做。因为我们在tarjan的过程中实际上就已经相当于求了一遍拓扑排序了。可以这么想,因为最后我们赋值scc的时候是从栈内弹出赋值的,也就是说越靠近叶子的节点越先被赋值,总的来看这不就是拓扑序的逆序吗?我们可以直接对比a和-a的拓扑序,哪个小就表明哪个是在越靠经根节点处被选中的,那么我们就优先选择哪个比较小的节点。

当然,因为这里我们存储的是拓扑的逆序,所以我们会优先选择哪个比较大的节点

一些代码处理的细节

虽然我们分析问题的时候经常会用a 或-a来表示某个变量的两种状态,但是数组的下标不能是负数。这里我们可以简单地表示-a为a+n,n就是点数。

如果完全按照每一种xi和xj的取值来写代码的话,就会是这个样子的:

for (int i=1;i<=m;i++) {
int a,va,b,vb;
scanf("%d %d %d %d",&a,&va,&b,&vb);
if (va && vb) { // a, b 都真,-a -> b, -b -> a
gpe[a+n].push_back(b);
gpe[b+n].push_back(a);
} else if (!va && vb) { // a 假 b 真,a -> b, -b -> -a
gpe[a].push_back(b);
gpe[b+n].push_back(a+n);
} else if (va && !vb) { // a 真 b 假,-a -> -b, b -> a
gpe[a+n].push_back(b+n);
gpe[b].push_back(a);
} else if (!va && !vb) { // a, b 都假,a -> -b, b -> -a
gpe[a].push_back(b+n);
gpe[b].push_back(a+n);
}
}

当然这么写是正确的,但是代码不可避免地有点冗长,这里我们可以使用位运算的写法可以缩短代码长度:

for(int i=1;i<=m;i++){
int a,va,b,vb;
scanf("%d %d %d %d",&a,&va,&b,&vb);
gpe[a+n*(va&1)].push_back(b+n*(vb^1));
gpe[b+n*(vb&1)].push_back(a+n*(va^1));
}

模板题AC代码:

//luogu p4782
#include <bits/stdc++.h>
using namespace std;
const int maxn=2000050;
struct edge{
int to;
edge(int to_){
to=to_;
}
};
vector<edge> gpe[maxn];
int dfn[maxn],low[maxn],ins[maxn],scc[maxn],size[maxn],cnt=0,sccn=0;
stack<int> s;
void tarjan(int u){
dfn[u]=low[u]=++cnt;
s.push(u);
ins[u]=1;
for(int i=0;i<gpe[u].size();i++){
int v=gpe[u][i].to;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}else if(ins[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u]){
ins[u]=0;
scc[u]=++sccn;
size[sccn]=1;
while(s.top()!=u){
scc[s.top()]=sccn;
ins[s.top()]=0;
size[sccn]+=1;//这里的size实际上是不需要的
s.pop();
}
s.pop();
}
return;
}
int n,m,oud[maxn];
int main(void){
scanf("%d %d",&n,&m);
memset(low,0x3f,sizeof(low));
memset(ins,0,sizeof(ins));
for(int i=1;i<=m;i++){
int a,va,b,vb;
scanf("%d %d %d %d",&a,&va,&b,&vb);
gpe[a+n*(va&1)].push_back(b+n*(vb^1));
gpe[b+n*(vb&1)].push_back(a+n*(va^1));
}
for(int i=1;i<=n*2;i++){
if(!dfn[i]){
tarjan(i);
}
}
for(int i=1;i<=n;i++){
if(scc[i]==scc[i+n]){
printf("IMPOSSIBLE");
return 0;
}
}
printf("POSSIBLE\n");
for(int i=1;i<=n;i++){
printf("%d ",scc[i]<scc[i+n]);
}
return 0;
}

个人的xbb

其实这个问题感觉和差分约束有一点神似,因为都是根据关系来转换到图上解决的问题

看到自己以前写的代码感觉还是太蠢了qaq,但是反正也懒得改,就直接贴上去罢了

2-SAT问题简述的更多相关文章

  1. 简述WebService的使用(二)

    上集回顾 上一篇我简单的介绍了一下整个WebService建立和后端访问的过程,如果感兴趣可以看一看:简述WebService的使用(一) //如有不懂请留言,觉得有用请点赞 内容提要 这一篇主要介绍 ...

  2. 简述 OAuth 2.0 的运作流程

    本文将以用户使用 github 登录网站留言为例,简述 OAuth 2.0 的运作流程. 假如我有一个网站,你是我网站上的访客,看了文章想留言表示「朕已阅」,留言时发现有这个网站的帐号才能够留言,此时 ...

  3. JavaScript单线程和浏览器事件循环简述

    JavaScript单线程 在上篇博客<Promise的前世今生和妙用技巧>的开篇中,我们曾简述了JavaScript的单线程机制和浏览器的事件模型.应很多网友的回复,在这篇文章中将继续展 ...

  4. Design Patterns Simplified - Part 3 (Simple Factory)【设计模式简述--第三部分(简单工厂)】

    原文链接:http://www.c-sharpcorner.com/UploadFile/19b1bd/design-patterns-simplified-part3-factory/ Design ...

  5. Android网络定位服务定制简述

    Android 添加高德或百度网络定位服务 Android的网络定位服务以第三方的APK方式提供服务,由于在国内Android原生自带的com.google.android.gms服务几乎处于不可用状 ...

  6. 《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述

    微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...

  7. 简述ASP.NET MVC原理

    1.为什么ASP.NET需要MVC? 因为随着网站的的数量级越来越大,原始的网站方式,这里指的是WebForm,在运行速度和维护性方面,以及代码量上面,越来越难以满足日益庞大的网站维护成本.代码的重构 ...

  8. Design Patterns Simplified - Part 2 (Singleton)【设计模式简述--第二部分(单例模式)】

    原文链接: http://www.c-sharpcorner.com/UploadFile/19b1bd/design-patterns-simplified-part-2-singleton/ De ...

  9. 【翻译】设计模式学习系列1---【Design Patterns Simplified: Part 1【设计模式简述:第一部分】】

    原文链接:http://www.c-sharpcorner.com/UploadFile/19b1bd/design-patterns-simplified-part1/ Design Pattern ...

  10. Android开发3:Intent、Bundle的使用和ListView的应用 、RelativeLayout(相对布局)简述(简单通讯录的实现)

    前言 啦啦啦~博主又来骚扰大家啦~大家是不是感觉上次的Android开发博文有点长呢~主要是因为博主也是小白,在做实验的过程中查询了很多很多概念,努力去理解每一个知识点,才完成了最终的实验.还有就是随 ...

随机推荐

  1. 百度云虚拟空间(BCH)

    百度云虚拟空间(BCH)上的一些默认配置 :first-child { margin-top: 0;}blockquote > :last-child { margin-bottom: 0;}i ...

  2. 2019-2020-1 20199329《Linux内核原理与分析》第七周作业

    <Linux内核原理与分析>第七周作业 一.本周内容概述: 对Linux系统如何创建一个新进程进行追踪 分析Linux内核创建一个新进程的过程 二.本周学习内容: 1.学习进程的描述 操作 ...

  3. 鸟哥Linux私房菜(基础篇)——第五章:首次登入与在线求助 man page笔记

    1.X Winsows与文本模式的切换 ●[Ctrl] + [Alt] + [F1] ~ [F6] :文字接口登入 tty1 ~ tty6 终端机.        ●[Ctrl] + [Alt] + ...

  4. 5.Python是怎么解释的?

    Python是怎么解释的? Python language is an interpreted language. Python program runs directly from the sour ...

  5. Shoutem旨在成为React Native移动应用领域的WordPress

    近日,Shoutem推出了新的基于React Native的应用构建器,为开发人员提供了移动应用领域的WordPress. \\ Shoutem让开发人员可以使用一个可视化环境快速创建基于React ...

  6. fullpage.js禁止滚动

    http://www.wenjiangs.com/doc/fullpage-method 转载于:https://www.cnblogs.com/hzz-/p/8268771.html

  7. 禅道部署(基于 Linux)

    1. 查看 Linux 服务器是 32位 还是 64位 的 getconf LONG_BIT 2. 禅道开源版安装包下载 下载站点1:# wget http://sourceforge.net/pro ...

  8. speedtest 测试服务器上传下载速度

    下载speedtest.py wget https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py 赋予执行权限 ...

  9. tinymce富文本编辑器整合到django

    第一步:定义表存图片路径 models.py class AdminIMG(models.Model):     filename = models.CharField(max_length=200, ...

  10. Python监控文件夹 && 发送邮件

    直接上代码: # python3 # -*- coding: utf-8 -*- # 2017/06/16 by luohan from email.mime.text import MIMEText ...