P4782 【模板】2-SAT 问题
题目大意
有 个布尔变量 ,另有 个需要满足的条件,每个条件的形式都是 「 为 true / false 或 为 true / false」。 比如 「 为真或 为假」、「 为假或 为假」。
2-SAT
问题的目标是给每个变量赋值使得所有条件得到满足。
解题思路
2-SAT
都是指给你许多约束条件,类似于二选一之类的,让你输出任意一种合法解。
如果是 选一,那就是 k-SAT
问题。
首先思考,如果是二选一的问题,那是不是这两个互相排斥的点不能连在一起?
解题流程:
1.对于所有两个互相排斥的点,就不能连边,将集合里没有明确关系的点就连一条边。
2.然后对每一个没有在上一遍 tarjan
遍历到的点都 tarjan
一遍。
3.判断是否有不可满足的解。
- 输出正确解。
输出方案时可以通过变量在图中的拓扑序确定该变量的取值。
如果变量 的拓扑序在 之后,那么取 值为真。
应用到 Tarjan
算法的缩点,即 所在 SCC
编号在 之前时,取 为真。
因为 Tarjan
算法求强连通分量时使用了栈,所以 Tarjan
求得的 SCC
编号相当于反拓扑序。
关于本题
编号 表示点为 。
编号 表示点为 。
AC CODE
阅读时请省略快读。
#include <bits/stdc++.h>
using namespace std;
/* --------------- fast io --------------- */ // begin
namespace Fastio
{
struct Reader
{
template <typename T>
Reader &operator>>(T &x)
{
char c = getchar();
T f = 1;
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
x = 0;
while (c >= '0' && c <= '9')
{
x = x * 10 + (c - '0');
c = getchar();
}
x *= f;
return *this;
}
Reader &operator>>(char &c)
{
c = getchar();
while (c == ' ' || c == '\n')
{
c = getchar();
}
return *this;
}
Reader &operator>>(char *str)
{
int len = 0;
char c = getchar();
while (c == ' ' || c == '\n')
{
c = getchar();
}
while (c != ' ' && c != '\n' && c != '\r')
{ // \r\n in windows
str[len++] = c;
c = getchar();
}
str[len] = '\0';
return *this;
}
Reader() {}
} cin;
const char endl = '\n';
struct Writer
{
template <typename T>
Writer &operator<<(T x)
{
if (x == 0)
{
putchar('0');
return *this;
}
if (x < 0)
{
putchar('-');
x = -x;
}
static int sta[111];
int top = 0;
while (x)
{
sta[++top] = x % 10;
x /= 10;
}
while (top)
{
putchar(sta[top] + '0');
--top;
}
return *this;
}
Writer &operator<<(char c)
{
putchar(c);
return *this;
}
Writer &operator<<(char *str)
{
int cur = 0;
while (str[cur])
putchar(str[cur++]);
return *this;
}
Writer &operator<<(const char *str)
{
int cur = 0;
while (str[cur])
putchar(str[cur++]);
return *this;
}
Writer() {}
} cout;
} // namespace Fastio
#define cin Fastio ::cin
#define cout Fastio ::cout
#define endl Fastio ::endl
/* --------------- fast io --------------- */ // end
#define _ 20005
int n, m, cnt_node, cntn;
int ans[2000005];
int cnt;
array<int, 2000005> head;
struct abc
{
int to, nxt;
};
array<abc, 2000005> dd;
array<bool, 2000005> vis;
array<int, 2000005> dfn, low, id;
stack<int> s;
inline void add(int u, int v)
{
dd[++cnt].to = v;
dd[cnt].nxt = head[u];
head[u] = cnt;
}
inline void tarjan(int u)
{
dfn[u] = low[u] = ++cnt_node;
s.push(u);
vis[u] = 1;
for (int e = head[u]; e; e = dd[e].nxt)
{
if (!dfn[dd[e].to])
{
tarjan(dd[e].to);
low[u] = min(low[dd[e].to], low[u]);
}
else if (vis[dd[e].to])
low[u] = min(low[u], dfn[dd[e].to]);
}
if (low[u] == dfn[u])
{
cntn++;
while (1)
{
int now = s.top();
s.pop();
vis[now] = 0;
id[now] = cntn;
if (now == u)
break;
}
}
}
int js(int x)
{
return (x % 2) ? x + 1 : x - 1;
}
signed main()
{
cin >> n >> m;
for(int i = 1; i <= m; ++i)
{
int a, b, c, d;
cin >> a >> b >> c >> d;
if(b && d)
{
add(a + n, c);
add(c + n, a);
}
else if(!b && d)
{
add(a, c);
add(c + n, a + n);
}
else if(b && !d)
{
add(a + n, c + n);
add(c, a);
}
else // !b && !d
{
add(a, c + n);
add(c, a + n);
}
}
for(int i = 1; i <= 2 * n; ++i)
if(!dfn[i]) tarjan(i);
for(int i = 1; i <= n; ++i)
if(id[i] == id[i + n])
{
puts("IMPOSSIBLE");
return 0;
}
puts("POSSIBLE");
for(int i = 1; i <= n; ++i)
cout << (id[i] < id[i + n]) << " ";
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122157
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效