题解:P4782 【模板】2-SAT
尝试用了新版格式。我发现氧洛谷在新版格式有不小 bug,在此催更。
定义
2-SAT,简单的说就是给出
例题引入:洛谷 P4782
有 true / false 或 true / false”。比如“
2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。
转化题意为:装饰一个房间,有
重点:建图
使用布尔方程表示上述问题。设
| 原式 | 建图 |
|---|---|
| ^ | |
| ^ | |
| ^ |
许多 2-SAT 问题都需要找出如
求解
思考如果两点在同一强连通分量里有什么含义。根据前文边的逻辑意义可知:若两点在同一强连通分量内,则这两点代表的条件要么都满足,要么都不满足。
建图周我们跑一遍 Tarjan 找 SCC,判断对于任意布尔变量
输出方案时可以通过变量在图中的拓扑序确定该变量的取值。如果变量
算法会把整张图遍历一遍,并且在结算答案时复杂度为
::::info[代码]
#include<cstdio>
#include<algorithm>
#include<stack>
using namespace std;
const int N=2e6+2;
int n,m,dfn[N],low[N],t,tot,head[N],a[N];
bool vis[N];
stack<int> s;
struct node{int to,Next;}e[N];
void adde(int u,int v){
e[++tot].to=v;
e[tot].Next=head[u];
head[u]=tot;
}
void Tarjan(int u){
dfn[u]=low[u]=++t;
s.push(u);
vis[u]=1;
for(int i=head[u];i;i=e[i].Next){
int v=e[i].to;
if(!dfn[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
int cur;
++tot;
do{
cur=s.top();
s.pop();
vis[cur]=0;
a[cur]=tot;
}while(cur!=u);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,I,J,A,B;i<=m;i++){
scanf("%d%d%d%d",&I,&A,&J,&B);
adde(A?I+n:I,B?J:J+n);
adde(B?J+n:J,A?I:I+n);
}
tot=0;
for(int i=1;i<=(n<<1);i++) if(!dfn[i]) Tarjan(i);
for(int i=1;i<=n;i++){
if(a[i]==a[i+n]){
printf("IMPOSSIBLE");
return 0;
}
}
puts("POSSIBLE");
for(int i=1;i<=n;i++){
putchar(a[i]<a[i+n]?'1':'0');
putchar(' ');
}
return 0;
}
::::