【图论】2-SAT 问题
目录
简介
做法
代码
简介
k-SAT(全称Satisfiability)问题,具体来说,给定 个具有真假的命题,给一些逻辑关系(例如 ),如果逻辑关系式子包含 个元,要求出 个命题的真假值满足所有逻辑关系。当 时,已经被证明为 问题,但是 时可以使用线性复杂度的算法解决,所以我们在这重点讨论 2-SAT 问题。
做法
注意到这样一个事实: ,同理, 。(详细可以参考数理逻辑)
被称为蕴含
如果将 个命题看成 个点,然后利用上面的事实建边的话,就可以转化为图论问题求解了。
具体来说,例如,有命题 ,逻辑关系为 ,我们将 拆成两个状态(图论中相应的两个点) ,分别表示 取真、取假, 用相同方式处理,那么逻辑关系可以转化为图论中的两条有向边: 。
用这样的方式,就可以将所给的命题以及逻辑关系转化为一个有向图了。
对这个有向图,我们采用 ,如果一个命题的两个状态 同时出现在同一个强连通分量中,问题无解(因为不可能有 直接或间接地蕴含 )
否则, 所在的强连通分量编号一定存在严格的偏序关系(通俗地说就是一定是一大一小),我们取编号小的那个状态作为命题 的取值即可。
下面简单说明这样取即可保证正确:
假如 ,由逆否命题性质,一定有 ,如果说 和 在同一强连通分量中,那么 和 一定在另一强连通分量中,不妨设 所在的强连通分量编号较小,我们选取了 。由强连通分量性质, 与 可以相互到达,所以 一定要被选取,而事实上由构造方式知 一定是被选取的,因此这样做能够保证正确性。
模板题:(一样的)
https://www.acwing.com/problem/content/2404/
https://www.luogu.com.cn/problem/P4782
代码
#include<bits/stdc++.h>
using namespace std;
inline void read(int &x) {
int s=0;x=1;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')x=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
x*=s;
}
const int N=2e6+5, M=2e6+5;
int n, m;
struct node{
int to, next;
}e[M];
int h[N], tot;
void add(int u, int v){
e[tot].to=v, e[tot].next=h[u], h[u]=tot++;
}
int ts, dfn[N], low[N];
int stk[N], top;
int id[N], cnt;
bool ins[N];
void tarjan(int u){
dfn[u]=low[u]=++ts;
stk[++top]=u, ins[u]=true;
for(int i=h[u]; ~i; i=e[i].next){
int go=e[i].to;
if(!dfn[go]){
tarjan(go);
low[u]=min(low[u], low[go]);
}else if(ins[go]) low[u]=min(low[u], dfn[go]);
}
if(dfn[u]==low[u]){
int y;
cnt++;
do{
y=stk[top--], ins[y]=false, id[y]=cnt;
}while(y!=u);
}
}
int res[N];
int main(){
memset(h, -1, sizeof h);
read(n), read(m);
while(m--){
int i, a, j, b; read(i), read(a), read(j), read(b);
i--, j--;
add(2*i+!a, 2*j+b), add(2*j+!b, 2*i+a);
}
for(int i=0; i<2*n; i++) if(!dfn[i]) tarjan(i);
for(int i=0; i<n; i++) if(id[2*i]==id[2*i+1]){
puts("IMPOSSIBLE");
return 0;
}else res[i]= id[2*i]>id[2*i+1];
puts("POSSIBLE");
for(int i=0; i<n; i++) printf("%d ", res[i]);
cout<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】