2-Sat
Posted handsome-zlk
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2-Sat相关的知识,希望对你有一定的参考价值。
先推两篇dalao资料:
https://wenku.baidu.com/view/afd6c436a32d7375a41780f2.html
https://blog.csdn.net/jarjingx/article/details/8521690
好像还有https://wenku.baidu.com/view/0f96c3daa58da0116c1749bc.html,不过我还没有看过
花了几天搞了搞这个东西
写一点小小的心得体会
由于本人是蒟蒻,而且这篇小笔记其实是留给自己看的,所以可能不会用什么高深的话去解释这个东西,也不会讲的非常详细,如果看完那两位大佬的博文还不是很懂,或许可以再看一看我的这篇笔记,希望能有所帮助
一、概念
至于2-Sat,它是解决一个类给了你一个图中一大坨关系,然后让你判断这些关系同时成立的图是否存在这样一类问题,为什么研究2-sat呢?无可置疑的是它很有用。为什么不研究3-sat乃至k更大的情况呢,因为它们已经被证明为是 NP完全问题了,在更多的情况下,2-sat不仅仅是元素个数最多的集合含有2个元素,而是每个集合都含有2个元素,且这2个元素不允许同时取出,这篇文章主要讨论的就是这样一种特殊的模型。这类题都是比较裸的,看一眼题就能知道要用2-Sat,所以可能并没有很多比赛考过这个东西。
二、算法流程&&说明
捋一遍2-sat方法流程
1.根据题意建图
连接若取a就必须取b这些路径
若条件是不能取a,你可以让a连到a’,矛盾即可
不懂为什么有人奇怪要建反向边,不是不建
2.Tarjan缩点
没什么好说的
缩起来的这一个点表示在这个环里面任取一个点就要取完这一个环,其实这是为了可以在图中进行拓扑排序和判断是否可行
3.判断是否存在
这个,嗯,如果有两个对应点在一个环里,就说明若取a必取a‘,矛盾
如果没有,就说明存在这样一个满足条件的图
4.拓扑排序
Tarjan缩点是个反拓扑排序,不必再排
5.根据拓扑排序输出方案
这个东西想了很久,发现自己过于zz,其实利用对称性即可证明这个东西,当a的拓扑序大于a‘时,只有这两种情况:
1)两者有路径相连,即若取a‘则必取a,故不能取a‘,只可取a
2)两者无路径相连,对称性这个东西其实那两位大佬都讲的很清楚,不再赘述,就直接引用一下两个结论:
由于点对称,边对称,则图对称,所以设a点有x个前序节点,有y个后序节点,则a’点有y个前序节点,有x个后序节点,而且互相对应
明确了这一点,其实就不难证明了,只需要将和a有关的所有节点通通取走,对应的通通不取,其实对其他的节点没有任何干扰,其他节点也只会出现这两种情况,所以可以简要证明拓扑排序的正确性
三、模板
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define rep(i,a,b) for(long long i=a;i<=b;i++) #define MAXN 2000500 using namespace std; typedef long long ll; ll n,m,fir[MAXN],to[MAXN],nxt[MAXN],tot=-1; ll dfn[MAXN],col[MAXN],low[MAXN],cnt,num,sta[MAXN],top; ll read(){ ll x=0; char ch=getchar(); while(‘0‘>ch || ‘9‘<ch) ch=getchar(); while(‘0‘<=ch && ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘; ch=getchar();} return x; } void ade(ll u,ll v){ to[++tot]=v; nxt[tot]=fir[u]; fir[u]=tot; } void Tarjan(ll x){ low[x]=dfn[x]=++num; sta[++top]=x; for(ll k=fir[x];k!=-1;k=nxt[k]){ if(!dfn[to[k]]){ Tarjan(to[k]); low[x]=min(low[x],low[to[k]]); } else if(!col[to[k]]) low[x]=min(low[x],dfn[to[k]]); } if(low[x]==dfn[x]){ col[x]=++cnt; while(sta[top]!=x) col[sta[top]]=cnt,--top; --top; } } bool twosat(){ rep(i,1,2*n) if(!dfn[i]) Tarjan(i); rep(i,1,n) if(col[i]==col[i+n]) return 0; return 1; } int main(){ memset(fir,-1,sizeof(fir)); scanf("%lld%lld",&n,&m); rep(i,1,m){ int e=read(),r=read(),t=read(),y=read(); ade(e+r*n,t+(1-y)*n); ade(t+y*n,e+(1-r)*n); } if(twosat()){ printf("POSSIBLE "); for(int i=1; i<=n; i++) printf("%d ",col[i]<col[i+n]); } else printf("IMPOSSIBLE"); return 0; }
四、一些题目
这些题目其实和板子区别不大
一、和平委员会
原题来自:POI 2001
根据宪法,Byteland 民主共和国的公众和平委员会应该在国会中通过立法程序来创立。 不幸的是,由于某些党派代表之间的不和睦而使得这件事存在障碍。
此委员会必须满足下列条件:
-
每个党派都在委员会中恰有 1 个代表,
-
如果 2 个代表彼此厌恶,则他们不能都属于委员会。
每个党在议会中有 2个代表。代表从 1 编号到 2n。 编号为 2i−1 和 2i 的代表属于第 i 个党派。
任务:写一程序读入党派的数量和关系不友好的代表对,计算决定建立和平委员会是否可能,若行,则列出委员会的成员表。
输入格式
第一行有两个非负整数 n 和 m。他们各自表示:党派的数量 n 和不友好的代表对 m。 接下来 m 行,每行为一对整数 a,b,表示代表 a,b 互相厌恶。
输出格式
如果不能创立委员会,则输出信息NIE
。若能够成立,则输出包括 n 个从区间 1 到 2n 选出的整数,按升序写出,每行一个,这些数字为委员会中代表的编号。
如果委员会能以多种方法形成,程序可以只输出它们的某一个。
样例
样例输入
3 2
1 3
2 4
样例输出
1
4
5
数据范围与提示
1≤n≤8000,0≤m≤20000,1≤a<b≤2n
嗯,其实只要BB一下建图方案
若取a则必取-b,若取b则必取-a
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define rep(i,a,b) for(int i=a;i<=b;i++) 6 using namespace std; 7 int n,m,to[40050],nxt[40050],fir[17000],tot; 8 int dfn[17000],low[17000],num,cnt,col[17000],sta[17000],top; 9 void ade(int u,int v){ 10 to[++tot]=v; 11 nxt[tot]=fir[u]; 12 fir[u]=tot; 13 } 14 void Tarjan(int x){ 15 dfn[x]=low[x]=++num; 16 sta[++top]=x; 17 for(int k=fir[x];k;k=nxt[k]){ 18 if(!dfn[to[k]]){Tarjan(to[k]); low[x]=min(low[to[k]],low[x]);} 19 else if(!col[to[k]]) low[x]=min(low[x],dfn[to[k]]); 20 } 21 if(low[x]==dfn[x]){ 22 col[x]=++cnt; 23 while(sta[top]!=x) col[sta[top]]=cnt,--top; 24 --top; 25 } 26 } 27 bool twosat(){ 28 rep(i,1,2*n) if(!dfn[i]) Tarjan(i); 29 rep(i,1,n) if(col[i*2]==col[i*2-1]) return 0; 30 31 return 1; 32 } 33 int main(){ 34 scanf("%d%d",&n,&m); 35 rep(i,1,m){ 36 int a,b,c=1,d=1; scanf("%d%d",&a,&b); 37 if(a&1) c=-1; if(b&1) d=-1; 38 ade(a,b-d); ade(b,a-c); 39 } 40 if(twosat()) rep(i,1,n) if(col[i*2]>col[i*2-1]) printf("%d ",i*2-1);else printf("%d ",i*2); 41 else printf("NIE"); 42 }
以上是关于2-Sat的主要内容,如果未能解决你的问题,请参考以下文章
POJ 3905 Perfect Election(2-sat)