2-SAT 学习笔记
2-SAT 学习笔记
有一类生活中的问题:
一个人邀请了 A,B,C,D 四个人来他的 party,但是 A 和 B 有矛盾,所以他俩不会一起来,C 和 D 也有矛盾不会一起来,要求找到一种合适的方式来邀请他们,判断是否有这种方案,并且找出这种方案。
把这个问题抽象一下,有
如果把这个说法再简化一下,就是条件
前置知识:强连通分量(本博客采用 Tarjan 算法)。
P4782 【模板】2-SAT 问题
题目描述
有 true
/ false
或 true
/ false
」。比如 「
2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。
输入格式
第一行两个整数
接下来
输出格式
如无解,输出 IMPOSSIBLE
;否则输出 POSSIBLE
。
下一行
样例 #1
样例输入 #1
3 1
1 1 3 0
样例输出 #1
POSSIBLE
0 0 0
提示
由于数据随机生成,可能会含有(10 0 10 0)之类的坑,但按照最常规写法的写的标程没有出错,各个数据点卡什么的提示在标程里。
Solution
此题就是最显然的
尝试建图,将每一个条件建成一个点,比如有两个点
考虑怎么输出方案。不难发现,如果
Code
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<23],*p1=buf,*p2=buf;
//#define int long long
using namespace std;
template<typename T> void read(T &k)
{
k=0;T flag=1;char b=getchar();
while (!isdigit(b)) {flag=(b=='-')?-1:1;b=getchar();}
while (isdigit(b)) {k=k*10+b-48;b=getchar();}
k*=flag;
}
template<typename T> void write(T k) {if (k<0) {putchar('-'),write(-k);return;}if (k>9) write(k/10);putchar(k%10+48);}
template<typename T> void writewith(T k,char c) {write(k);putchar(c);}
const int _SIZE=2e6;
int n,m;
struct EDGE{
int nxt,to;
}edge[(_SIZE<<1)+5];
int tot,head[_SIZE+5];
void AddEdge(int x,int y) {edge[++tot]=(EDGE){head[x],y};head[x]=tot;}
int dfn[_SIZE+5],bl[_SIZE+5],low[_SIZE+5],cnt;
bool vis[_SIZE+5];
stack<int> s;
void tarjan(int x)
{
dfn[x]=low[x]=++cnt;
vis[x]=1,s.push(x);
for (int i=head[x];i;i=edge[i].nxt)
{
int twd=edge[i].to;
if (!dfn[twd]) tarjan(twd),low[x]=min(low[x],low[twd]);
else if (vis[twd]) low[x]=min(low[x],dfn[twd]);
}
if (low[x]==dfn[x])
{
int v;cnt++;
do{
v=s.top(),s.pop(),vis[v]=0;
bl[v]=cnt;
}while(v!=x);
}
}
int Num(int x,int flag) {return x+flag*n;}//用于建图计算点,如果值为0则为x,值为1就为x+n
signed main()
{
read(n),read(m);
for (int i=1;i<=m;i++)
{
int a,b,c,d;read(a),read(b),read(c),read(d);
AddEdge(Num(a,b),Num(c,!d)),AddEdge(Num(c,d),Num(a,!b));
}
for (int i=1;i<=(n<<1);i++) if (!dfn[i]) tarjan(i);
for (int i=1;i<=n;i++)
if (bl[i]==bl[i+n]) return puts("IMPOSSIBLE")&0;
puts("POSSIBLE");
for (int i=1;i<=n;i++)
writewith(bl[i]<bl[i+n],' ');
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步