P4782 【模板】2-SAT 问题

原题传送门

题目大意

nn 个布尔变量 x1xnx_1\sim x_n,另有 mm 个需要满足的条件,每个条件的形式都是 「xix_i 为 true / false 或 xjx_j 为 true / false」。 比如 「x1x_1 为真或 x3x_3 为假」、「x7x_7 为假或 x2x_2 为假」。

2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。

解题思路

2-SAT 都是指给你许多约束条件,类似于二选一之类的,让你输出任意一种合法解。

如果是 kk 选一,那就是 k-SAT 问题。

首先思考,如果是二选一的问题,那是不是这两个互相排斥的点不能连在一起?

解题流程:

1.对于所有两个互相排斥的点,就不能连边,将集合里没有明确关系的点就连一条边。

2.然后对每一个没有在上一遍 tarjan 遍历到的点都 tarjan 一遍。

3.判断是否有不可满足的解。

  1. 输出正确解。

输出方案时可以通过变量在图中的拓扑序确定该变量的取值。

如果变量 x-x 的拓扑序在 xx 之后,那么取 xx 值为真。

应用到 Tarjan 算法的缩点,即 xx 所在 SCC 编号在 x-x 之前时,取 xx 为真。

因为 Tarjan 算法求强连通分量时使用了栈,所以 Tarjan 求得的 SCC 编号相当于反拓扑序。

关于本题

编号 1n1 \to n 表示点为 11

编号 n+12nn+1 \to 2n 表示点为 00

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;
}
posted @   蒟蒻orz  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示