luogu 2-SAT 问题
Posted liguanlin1124
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu 2-SAT 问题相关的知识,希望对你有一定的参考价值。
题目大意:给出n个bool变量,以及m个条件,条件为x,vx,y,vy,表示 x == vx || y == vy 。
求匹配。
题解:
最近新学了一下2-SAT算法。2-SAT指有若干个bool变量(显然有1/0两个值),还给出若干限定条件,比如:
t1 || t2
t1 || !t2
t1 && t2
t1 && -t2
等等。
然后要求找匹配方案。
首先大家应该听过差分约束,差分约束是用最短路处理数的大小关系等问题。
而2-SAT就高级多了,他是将关系映射到图上,然后用tarjan等方法判断情况是否存在。
具体操作是:
若t1成立则t2一定成立,就从t1向t2连一条边。
比如本题(t1成立或t2成立):
! t1 -> t2
! t2 -> t1
然后看看i和i+n( !i )是否在一个集里,在的话就不合法。
最后跑tarjan缩点,按拓扑逆序处理状态。由于tarjan是正向跑的,那就在bel [ i ]<bel[ n - i ]时输出1,要么输出0。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 1000050 int n,m,hed[2*N],cnt; struct EG { int to,nxt; }e[4*N]; void ae(int f,int t) { e[++cnt].to = t; e[cnt].nxt = hed[f]; hed[f] = cnt; } int dep[2*N],low[2*N],tim; int s[2*N],tl; bool vis[2*N]; int bel[2*N],bc; void tarjan(int u) { dep[u]=low[u]=++tim; s[++tl]=u; vis[u]=1; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(!dep[to]) { tarjan(to); low[u]=min(low[u],low[to]); }else if(vis[to]) { low[u]=min(low[u],dep[to]); } } if(dep[u]==low[u]) { bc++; int c=-1; while(c!=u) { c=s[tl--]; vis[c]=0; bel[c]=bc; } } } int main() { scanf("%d%d",&n,&m); int x,vx,y,vy; for(int i=1;i<=m;i++) { scanf("%d%d%d%d",&x,&vx,&y,&vy); ae(x+vx*n,y+(!vy)*n); ae(y+vy*n,x+(!vx)*n); } for(int i=1;i<=2*n;i++) if(!dep[i]) tarjan(i); for(int i=1;i<=n;i++) { if(bel[i]==bel[i+n]) { printf("IMPOSSIBLE "); return 0; } } printf("POSSIBLE "); for(int i=1;i<=n;i++) { printf("%d ",bel[i]<bel[i+n]); } printf(" "); return 0; }
以上是关于luogu 2-SAT 问题的主要内容,如果未能解决你的问题,请参考以下文章