2-SAT 问题
定义#
SAT是适定性(Satisfiability)问题的简称 。一般形式为k-适定性问题,简称 k-SAT。
可以证明,当
我们通俗的说,有
这里的限制例如:选
也就是“
而求解 2-SAT 的解就是求出满足所有限制的一组答案。
建图#
我们把
假如说我们有一个限制条件:“
那么这说明
这时我们从
只有在关系明确的时候才能建边
拿上面的限制来说,如果当
为什么不从
因为当其中一个值为
若 “
可以简单总结为:其中一个不成立则另一个一定成立(这是明确的关系)
如果出现类似
求解#
我们通常是跑一遍 tarjan 求强连通分量,如果要是有一个点
P4782 【模板】2-SAT 问题#
code:
#include<bits/stdc++.h>
#define int long long
#define N 4000100
using namespace std;
int head[N],cnt,n,m,f[N],dep[N],tp[N],tot;
struct sb{int u,v,next;}e[N];
inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){f=ch!='-';ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return f?x:-x;}
inline void add(int u,int v){e[++cnt].u=u;e[cnt].v=v;e[cnt].next=head[u];head[u]=cnt;}
inline int fid(int x){if(f[x]==x)return x;return f[x]=fid(f[x]);}
inline void dfs(int x)
{
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].v;
if(!dep[v])dep[v]=dep[x]+1,dfs(v);
if(dep[fid(v)]>0)
{
if(dep[fid(x)]<dep[f[v]])f[f[v]]=f[x];
else f[f[x]]=f[v];
}
}
dep[x]=-1,tp[x]=++cnt;
}
signed main()
{
n=read();m=read();
for(int i=1;i<=2*n;i++)f[i]=i;
for(int i=1;i<=m;i++)
{
int a=read(),b=read(),c=read(),d=read();
add(a+n*(b&1),c+n*(d^1));
add(c+n*(d&1),a+n*(b^1));
}
for(int i=1;i<=2*n;i++)if(!dep[i])dfs(i);
for(int i=1;i<=n;i++)if(fid(i)==fid(i+n))return cout<<"IMPOSSIBLE"<<endl,0;
cout<<"POSSIBLE"<<endl;
for(int i=1;i<=n;i++)
{
int ii=i+n;
if(tp[fid(i)]<tp[fid(ii)])cout<<"1 "<<endl;
else cout<<"0 "<<endl;
}
return 0;
}
tarjan 版:
#include<bits/stdc++.h>
#define N 4000100
using namespace std;
int n,m,ti,ans,head[N],nxt[N],to[N],dfn[N],low[N];
int flag[N],vis[N],cnt,sd[N],stk[N],top;
inline void add(int u,int v){to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;}
void tarjan(int x)
{
cnt=0;
dfn[x]=low[x]=++ti;
vis[x]=flag[x]=1;stk[++top]=x;
for(int i=head[x];i;i=nxt[i])
{
int v=to[i];
if(!dfn[v])tarjan(v),low[x]=min(low[x],low[v]);
else if(vis[v])low[x]=min(low[x],dfn[v]);
}
if(dfn[x]==low[x])
{
int y;cnt++;
while(1)
{
y=stk[top--];
sd[y]=cnt;
vis[y]=0;
if(x==y)break;
}
}
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int a,b,c,d;
cin>>a>>b>>c>>d;
add(a+n*b,c+n*(1^d));
add(c+n*d,a+n*(1^b));
}
for(int i=1;i<=2*n;i++)
if(!flag[i])tarjan(i);
// for(int i=1;i<=2*n;i++)
// cout<<sd[i]<<' ';
// cout<<endl;
for(int i=1;i<=n;i++)
if(sd[i]==sd[i+n]){cout<<"IMPOSSIBLE"<<endl;return 0;}
cout<<"POSSIBLE"<<endl;
for(int i=1;i<=n;i++)
cout<<(sd[i]<sd[i+n])<<" ";
return 0;
}
作者: 北烛青澜
出处:https://www.cnblogs.com/Multitree/p/17334406.html
本站使用「CC BY 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效