2-SAT 1
2-SAT 模板
有
另有 true
/ false
或 true
/ false
」。
比如 「
一种最直接的方式就是暴力搜,时间复杂度
已经被证明的就是
但是
判解
图论的一个非常重要的内容就是建图
我们把每个变量看成一个点,方程看作一条边
直接连边?显然会麻烦好多
这里的做法是拆点,
就是
而对应的,一个条件也会被拆成:
条件本身和它的逆否
从取
它的实际含义就是"如果取
这样的好处不仅是容易理解,我们还会发现:
如果两个对立的点在同一个强连通分量,显然无解
实际含义就是"如果这个点取一个值并且还要满足所有条件,那么这个点必须取这个值的反面"
于是我们只需要一遍
构造可行解
听论文说,构造一组可行解,
就是从缩完点以后的
用下一个才学的
就是
于是选
模板
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int o=2222222*2;
int n,m;
struct Graph{
struct edge{
int t;
int n;
}p[o];
int h[o],cnt;
int d[o],l[o],s[o],v[o],c[o],top,sum,num;
void add(int s,int t){
cnt++;
p[cnt].t=t;
p[cnt].n=h[s];
h[s]=cnt;
}
void Tarjan(int x){
d[x]=l[x]=++sum;
v[x]=1;
s[++top]=x;
for(int i=h[x];i;i=p[i].n){
int y=p[i].t;
if(!d[y]){
Tarjan(y);
l[x]=min(l[x],l[y]);
}
else if(v[y]){
l[x]=min(l[x],d[y]);
}
}
if(l[x]==d[x]){
int y;
num++;
do{
y=s[top--];
v[y]=0;
c[y]=sum;
}while(y!=x);
}
}
bool find(){
for(int i=1;i<=n;i++){
if(c[i]==c[i+n]){
return 0;
}
}
return 1;
}
void make(){
for(int i=1;i<=n;i++){
if(c[i]>c[i+n]){
printf("1 ");
}
else{
printf("0 ");
}
}
}
}G;
int read(){
int i=1,j=0;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-')i=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
j=j*10+ch-48;
ch=getchar();
}
return i*j;
}
void in(){
n=read(),m=read();
int a,b,x,y;
for(int i=1;i<=m;i++){
a=read(),x=read();
b=read(),y=read();
G.add(a+(!x)*n,b+y*n);
G.add(b+(!y)*n,a+x*n);
}
}
void work(){
for(int i=1;i<=2*n;i++){
if(!G.d[i]){
G.Tarjan(i);
}
}
if(G.find()){
puts("POSSIBLE");
return ;
}
puts("IMPOSSIBLE");
exit(0);
}
void out(){
G.make();
}
int main(){
in();
work();
out();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通