Description:
有n个布尔变量(x_1)~(x_n),另有m个需要满足的条件,每个条件的形式都是“(x_i)为true/false或(x_j)为true/false”。比如“(x_1)为真或(x_3)为假”、“(x_7)为假或(x_2)为假”。2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。
Hint:
(1le n,mle 10^6)
Solution:
模板题,详见代码
#include <algorithm>
#include <cmath>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
const int mxn=2e6+5;
int n,m,tot,cnt,col;
int hd[mxn],bl[mxn],dfn[mxn],low[mxn],ins[mxn];
stack<int > st;
struct ed {
int to,nxt;
}t[mxn<<1];
inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}
inline void add(int u,int v) {
t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
}
void tj(int u)
{
dfn[u]=low[u]=++tot; st.push(u); ins[u]=1;
for(int i=hd[u];i;i=t[i].nxt) {
int v=t[i].to;
if(!dfn[v]) tj(v),chkmin(low[u],low[v]);
else if(ins[v]) chkmin(low[u],dfn[v]);
}
if(dfn[u]==low[u]) {
++col;
do{
bl[u]=col; u=st.top();
st.pop(); ins[u]=0;
} while(low[u]!=dfn[u]);
}
} //tarjan基本操作,没什么好说的
int main()
{
scanf("%d%d",&n,&m); int u,v,x,y;
for(int i=1;i<=m;++i) {
scanf("%d%d%d%d",&u,&x,&v,&y);
add(u+n*(x^1),v+n*y);
add(v+n*(y^1),u+n*x); //建边,很好懂的
}
for(int i=1;i<=2*n;++i)
if(!dfn[i]) tj(i);
for(int i=1;i<=n;++i)
if(bl[i]==bl[i+n]) {
puts("IMPOSSIBLE");
return 0;
}
puts("POSSIBLE");
for(int i=1;i<=n;++i)
printf("%d ",bl[i]>bl[i+n]); //按较大拓扑序输出答案
return 0;
}