当前位置: 首页 > news >正文

LGP4782 [LG TPLT] 2-SAT 学习笔记

LGP4782 [LG TPLT] 2-SAT 学习笔记

Luogu Link

前言

为什么这个时候才把这个板子过了呢?

……大概是因为以前题解的代码长得太难看了?

……这是借口吗?

题意简述

\(n\) 个布尔变量与 \(m\) 个需要满足的条件。每个条件的形式都形如 \(x_i=a_k\lor x_j=b_k\)。其中 \(a_k\)\(b_k\) 取值为 \(0\)\(1\)

问能否给出使得一组方案满足所有要求。若可以,给出一组方案。

做法解析

图论建模。

\(x_i=a_k\lor x_j=b_k\) 可以写成:“若 \(x_i\) 不满足 \(a_k\)\(x_j\) 必须满足 \(b_k\),若 \(x_j\) 不满足 \(b_k\)\(x_i\) 必须满足 \(a_k\)”。我们把问题放到图论上,令结点 \(i\) 表示 \(x_i=1\) 的情况,结点 \(i+n\) 表示 \(x_i=0\) 的情况,于是我们就可以连出两条边:\(i_{\neg a_k}\to j_{b_k}\)\(j_{\neg b_k}\to i_{a_k}\)。然后跑强连通分量。

为什么是强连通分量呢?\(u\to v\) 意味着若 \(u\)\(v\),也即 \(u\)\(v\) 取值。我们对于每一对 \((i,i+n)\) 都需要“激活”其中的一个点(要么 \(i\) 为真成立,要么 \(i\) 为假成立),激活一个点后它能到达的所有点的真假也会与它一样。你处理完强连通分量之后若 \(x\)\(x+n\) 处于同一强连通分量中即说明无解,因为无论你激活其中的哪个都避免不了另一个被激活。

代码实现

#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=1e6+5;
int N,M,X,Y,ya,yb,na,nb;
vector<int> Gr[MaxN<<1];
int dfn[MaxN<<1],low[MaxN<<1],stk[MaxN<<1],ktp;
int tot,ccnt,bel[MaxN<<1];
void tarjan(int u){dfn[u]=low[u]=++tot,stk[++ktp]=u;for(auto v : Gr[u]){if(!dfn[v])tarjan(v),minner(low[u],low[v]);else if(!bel[v])minner(low[u],dfn[v]);}if(dfn[u]==low[u]){ccnt++;int v;for(int v;ktp;){v=stk[ktp--],bel[v]=ccnt;if(v==u)break;}}
}
bool twosat(int n){for(int i=1;i<=2*n;i++)if(!dfn[i])tarjan(i);for(int i=1;i<=n;i++)if(bel[i]==bel[i+n])return false;return true;
}
int main(){readis(N,M);for(int i=1;i<=M;i++){readis(X,ya,Y,yb);na=ya^1,nb=yb^1;Gr[X+na*N].push_back(Y+yb*N);Gr[Y+nb*N].push_back(X+ya*N);}if(twosat(N)){puts("POSSIBLE");for(int i=1;i<=N;i++)writip(bel[i]>bel[i+N]);}else puts("IMPOSSIBLE");return 0;
}
http://www.vanclimg.com/news/11.html

相关文章:

  • Biomu测试手册
  • 老车子ce导航 瑞风s5换大屏安卓导航
  • 老安卓机子延年益寿 更新webview和let x1根证书
  • 手把手玩转本地大模型:Ollama+DeepSeek+Dify 零门槛全流程指南
  • 6N90-ASEMI电源管理专用6N90
  • Biomu测试手册
  • 老车子ce导航 瑞风s5换大屏安卓导航
  • 老安卓机子延年益寿 更新webview和let x1根证书
  • 手把手玩转本地大模型:Ollama+DeepSeek+Dify 零门槛全流程指南
  • 6N90-ASEMI电源管理专用6N90