2-sat小结


原文作者:老K

原文传送门


2-sat是什么

一类问题是这样的:

(两个符号的意思 \(\lor \ or,\land \ and\))

有n个布尔变量,现在对它们做出限制,比如\(a_i=1,a_i \lor a_j=1\),求一组可行的解。

假设限制元素最多的限制限制了k个元素,这个问题就被称为k-sat问题。

可以证明(然而我不会),\(k>2\)时是NPC的。


基础想法

把每个变量\(a_i\)拆成2个点\(i_0,i_1\),表示它为1或0

每个变量就变成了一个集合。要求在每个集合里选一个元素,满足所有限制。

然后有向边\(<u,v>\)表示若选u则选v。

\(a_i=1\)型限制

连\(<i_0,i_1>\)。

\(a_i=0\)则反过来。

\(a_i=a_j\)限制

连\(<i_0,j_0><j_0,i_0><i_1,j_1><j_1,i_1>\)

\(a_i\not=a_j\)限制

连\(<i_0,j_1><j_0,i_1><i_1,j_0><j_1,i_0>\)

\(a_i\lor a_j=1\)或者\(a_i\land a_j =0\)限制

对于前者,连\(<i_0,j_1><j_0,i_1>\)

后者显然是交换0,1

\(a_i\lor a_j=0\)或者\(a_i\land a_j =1\) 限制

拆开,转化为\(a_i=1\)型限制

其实都很显然是吧。


算法1

有一个很显然的结论:设\(u'\)表示u所在集合的另一个元素。

如果存在\(<u,v>\)则一定存在\(<v',u'>\)(对称性)

那么我们可以按照顺序枚举每一个布尔变量。

假设它是0,然后沿着单向边计算它影响的元素,如果没有问题就是0,并且计算它影响的元素的值。

否则假设它是1,如果没问题就是1,并且计算它影响元素的值。

否则无解。

由于对称性以及边是单向的,可以证明这个算法的正确性。(或者感性理解)

时间复杂度\(O(nm)\)其中n是点数m是边数。

当然0,1的顺序是可以交换的。

这个算法可以求出字典序最小的解。

在算之前,按照每个变量0,1编号较小值从小到大排序。

然后枚举要先枚举每个变量编号较小的那个点。


算法2

有没有更快的算法呢?

当然是有的。

我们可以先tarjan 强连通分量缩点。

那么同一个强连通分量里,点的选择情况是一样的(选则都选,不选则都不选)。

由对称性可知如果\(u,v\)在同一个强连通分量里,那么\(u',v'\)也在同一个强连通分量里。

如果\(u,u'\)在同一个强连通分量里,那么无解。

否则考虑,缩完点后得到了一个DAG,由两个边相反的DAG组成。

我们可以通过拓扑排序,每次找一个没有出边的分量,如果它里面点的对称点没有被选择,那么执行如下操作:

选择它里面的所有点。

把它扔掉。(把所有到它的边断掉)

可以发现是对的。

时间复杂度\(O(n+m)\),通常用来计算可行解或者判断可行性。


算法3(黑科技)

不难发现,在缩完点后,如果u能到达v,那么在tarjan 中,u一定在v之后被找到。

于是我们可以在拓扑排序中,每次取能取的,编号最小的分量,

显然,如果一个分量\(u\)和分量\(v\)是对称的,那么如果\(u<v\),会选择u,否则会选择v。

那么就不用重建图拓扑排序了。

常数优化/代码量优化效果还是很明显的。


例题

满汉全席

模板题。


NOI 2017 Day2T1 游戏

之所以用UOJ是因为ex test巨强无比。

发现有一些地图是X,3种都可以,但是个数不超过8.

我们可以把X转化为A或B。

枚举每个X转化为A还是B,跑2-SAT就可以了。

/*
Authlor: CNYALI_LK
LANG: C++
PROG: 317.cpp
Mail: cnyalilk@vip.qq.com
*/
#include<bits/stdc++.h>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define DEBUG printf("Passing [%s] in LINE %d\n",__FUNCTION__,__LINE__)
#define Debug debug("Passing [%s] in LINE %d\n",__FUNCTION__,__LINE__)
#define all(x) x.begin(),x.end()
using namespace std;
const double eps=1e-8;
const double pi=acos(-1.0);
typedef long long ll;
typedef pair<int,int> pii;
template<class T>int chkmin(T &a,T b){return a>b?a=b,1:0;}
template<class T>int chkmax(T &a,T b){return a<b?a=b,1:0;}
template<class T>T sqr(T a){return a*a;}
template<class T>T mmin(T a,T b){return a<b?a:b;}
template<class T>T mmax(T a,T b){return a>b?a:b;}
template<class T>T aabs(T a){return a<0?-a:a;}
#define min mmin
#define max mmax
#define abs aabs
int read(){
int s=0,base=1;
char c;
while(!isdigit(c=getchar()))if(c=='-')base=-base;
while(isdigit(c)){s=s*10+(c^48);c=getchar();}
return s*base;
}
char rc(){
char c;
while(!isalpha(c=getchar()));
return c;
}
void rs(char *s){
while(!isalpha(*s=getchar()))++s;
while(isalpha(*s))*(++s)=getchar();
*s=0;
}
char WriteIntBuffer[1024];
template<class T>void write(T a,char end){
int cnt=0,fu=1;
if(a<0){putchar('-');fu=-1;}
do{WriteIntBuffer[++cnt]=fu*(a%10)+'0';a/=10;}while(a);
while(cnt){putchar(WriteIntBuffer[cnt]);--cnt;}
putchar(end);
}
struct _limit{
int a,b,ax,bx;
};
_limit a[102424];
char s[102424];
_limit limit(){
_limit x;
x.a=read()-1;
x.ax=rc();
x.b=read()-1;
x.bx=rc();
return x;
}
int h[102424];
int beg[102424],to[233333],lst[233333],dfn[102423],low[102423],no[102423];
int blocks,e,t;
void add(int u,int v){
to[++e]=v;
lst[e]=beg[u];
beg[u]=e;
}
int stk[102424],*top=stk;
void dfs(int x){
dfn[x]=low[x]=++t;
*(++top)=x;
flor(int i=beg[x];i;i=lst[i])
if(dfn[to[i]]){
if(!no[to[i]])
chkmin(low[x],dfn[to[i]]);
}else{
dfs(to[i]);
chkmin(low[x],low[to[i]]);
}
if(dfn[x]==low[x]){
++blocks;
do{
no[*(--top+1)]=blocks;
}while(*(top+1)!=x);
}
} int main(){
#ifdef cnyali_lk
freopen("317.in","r",stdin);
freopen("317.out","w",stdout);
#endif
int n,d,m;
n=read();
d=read();
rs(s);
int xs=0;
flor(int i=0;i<n;++i){
if(s[i]=='x'){h[xs]=i;++xs;}
}
m=read();
flor(int i=1;i<=m;++i){
a[i]=limit();
}
int un=1<<d,u,v;
flor(int j=0;j<un;++j){
flor(int i=0;i<d;++i)s[h[i]]='a'+!!(j&(1<<i));
flor(int i=0;i<n+n;++i)beg[i]=dfn[i]=low[i]=no[i]=0;
blocks=e=t=0;
flor(int i=1;i<=m;++i){
if(a[i].ax-'A'==s[a[i].a]-'a')continue;
if(a[i].bx-'A'==s[a[i].b]-'a'){
int u=a[i].a*2+(a[i].ax-'A'-(a[i].ax-'A'>=s[a[i].a]-'a'));
add(u,u^1);
}
else{
int u=a[i].a*2+(a[i].ax-'A'-(a[i].ax-'A'>=s[a[i].a]-'a'));
int v=a[i].b*2+(a[i].bx-'A'-(a[i].bx-'A'>=s[a[i].b]-'a'));
add(u,v);
add(v^1,u^1);
}
}
flor(int i=0;i<n+n;++i)if(!dfn[i])dfs(i);
int ok=1;
flor(int i=0;i<n;++i)if(no[i<<1]==no[i<<1|1])ok=0;
if(ok){
flor(int i=0;i<n;++i){
int ans=(no[i<<1]>no[i<<1|1]);
ans+=(ans>=s[i]-'a');
putchar(ans+'A');
}
return 0;
}
}
printf("-1\n");
return 0;
}

\({\Huge\color{Gold}{老K太强了QAQ}}\)

(转)2-SAT小结的更多相关文章

  1. python datetime 时间日期处理小结

    python datetime 时间日期处理小结 转载请注明出处:http://hi.baidu.com/leejun_2005/blog/item/47f340f1a85b5cb3a50f5232. ...

  2. python formatters 与字符串 小结 (python 2)

    最近学习python 2 ,觉得有必要小结一下关于字符串处理中的formatters, 转载请声明本文的引用出处:仰望大牛的小清新 0.%进行变量取值使用的时机 在python中,如果我们只是需要在字 ...

  3. 从零开始编写自己的C#框架(26)——小结

    一直想写个总结,不过实在太忙了,所以一直拖啊拖啊,拖到现在,不过也好,有了这段时间的沉淀,发现自己又有了小小的进步.哈哈...... 原想框架开发的相关开发步骤.文档.代码.功能.部署等都简单的讲过了 ...

  4. Python自然语言处理工具小结

    Python自然语言处理工具小结 作者:白宁超 2016年11月21日21:45:26 目录 [Python NLP]干货!详述Python NLTK下如何使用stanford NLP工具包(1) [ ...

  5. java单向加密算法小结(2)--MD5哈希算法

    上一篇文章整理了Base64算法的相关知识,严格来说,Base64只能算是一种编码方式而非加密算法,这一篇要说的MD5,其实也不算是加密算法,而是一种哈希算法,即将目标文本转化为固定长度,不可逆的字符 ...

  6. iOS--->微信支付小结

    iOS--->微信支付小结 说起支付,除了支付宝支付之外,微信支付也是我们三方支付中最重要的方式之一,承接上面总结的支付宝,接下来把微信支付也总结了一下 ***那么首先还是由公司去创建并申请使用 ...

  7. iOS 之UITextFiled/UITextView小结

    一:编辑被键盘遮挡的问题 参考自:http://blog.csdn.net/windkisshao/article/details/21398521 1.自定方法 ,用于移动视图 -(void)mov ...

  8. K近邻法(KNN)原理小结

    K近邻法(k-nearst neighbors,KNN)是一种很基本的机器学习方法了,在我们平常的生活中也会不自主的应用.比如,我们判断一个人的人品,只需要观察他来往最密切的几个人的人品好坏就可以得出 ...

  9. scikit-learn随机森林调参小结

    在Bagging与随机森林算法原理小结中,我们对随机森林(Random Forest, 以下简称RF)的原理做了总结.本文就从实践的角度对RF做一个总结.重点讲述scikit-learn中RF的调参注 ...

  10. Bagging与随机森林算法原理小结

    在集成学习原理小结中,我们讲到了集成学习有两个流派,一个是boosting派系,它的特点是各个弱学习器之间有依赖关系.另一种是bagging流派,它的特点是各个弱学习器之间没有依赖关系,可以并行拟合. ...

随机推荐

  1. 微信公众平台PHP示例一

    <?php /** * Created by PhpStorm. * User: Administrator * Date: 2015-12-18 * Time: 21:51 */ define ...

  2. 一个简单的AXIS远程调用Web Service示例

    我们通常都将编写好的Web Service发布在Tomcat或者其他应用服务器上,然后通过浏览器调用该Web Service,返回规范的XML文件.但是如果我们不通过浏览器调用,而是通过客户端程序调用 ...

  3. SpringMVC总结二:Controller的请求映射方式(RequestMapping)简单介绍

    在SpringMVC总结一:快速入门的基础上简单介绍一下请求映射的方式: 1,标准映射规则 1. @RequestMapping可以设置在类上,也可以设置在方法上 2. 请求的映射规则是:类上的Req ...

  4. MySQL日期数据类型总结

    MySQL:MySQL日期数据类型.MySQL时间类型使用总结 MySQL 日期类型:日期格式.所占存储空间.日期范围 比较. 日期类型        存储空间      日期格式           ...

  5. laravel 中的Gates,以及修改模型

    Gates 是一个用于判断用户是否有权进行某项操作的闭包,通常使用Gate 门面定义在 App\Providers\AuthServiceProvider类中.Gates 总是接收用户实例作为第一个参 ...

  6. The 'Microsoft Jet OLEDB 4.0 Provider' is not registered on the local machine

    在一台Win7 64位的操纵系统上部署的C# Web系统,操作Excel,批量导入数据,报错,提示错误信息: The ‘Microsoft Jet OLEDB 4.0 Provider' is not ...

  7. 利用osmosis导出osm城市数据

    转载(未测试) 方法核心就是利用osmosis的导出指定功能,即是从大范围导出小范围的基本用例. 我们只需要知道我们所需要提取的城市的经纬度范围, 例如广州市的经纬度范围是北纬22.26~23.56度 ...

  8. hdu 4286 (list的reverse时间复杂度为n)

    list 的翻转reverse源码: // 将链表倒置 // 其算法核心是历遍链表, 每次取出一个结点, 并插入到链表起始点 // 历遍完成后链表满足倒置 template <class T, ...

  9. 黑盒测试实践-任务进度-Day02

    使用工具 selenium 小组成员 华同学.郭同学.穆同学.沈同学.覃同学.刘同学 任务进度 在经过了昨天的基本任务分配之后,今天大家就开始了各自的内容,以下是大家任务的进度情况汇总. 华同学(任务 ...

  10. VIVADO生成MCS

    tcl console里面执行 write_cfgmem -format mcs -interface spix4 -size 128 -loadbit "up 0 E:/x.bit&quo ...