[CF468B] Two Sets

[CF468B] Two Sets - 2-sat

Description

给定 (n) 个数字,要划分成 (A,B) 两个集合。要求对任意 (x),若 (x)(A) 中则 (a-x) 也在 (A) 中,若 (x)(B) 中则 (b-x) 也在 (B) 中。保证数互不相同。

Solution

2-sat,点 (i) 表示第 (a_i)(A) 中,点 (i+n) 表示 (a_i)(B)

对于每个数 (a_i),如果 (a_j=a-a_i),那么 (i o j)

对于每个数 (a_i),如果 (a_j=b-a_i),那么 (i+n o j+n)

记录一下中间一个搞错了的地方,实际上也是经常错的(好像以前干过类似事情但自己忘了)
2-sat 中,当我们正向考虑选 x 必须选 y 时,实际上也意味着选 y' 必须选 x'
如果不连这条边会出问题

#include <bits/stdc++.h>
using namespace std;

#define reset(a) memset((a), 0, sizeof((a)))

const int N = 4001000;
struct edge
{
    int to, next;
} e[N];
int flag = 0;
int head_for[N], tot, head_back[N];
int n, a, b, x[N], m, cnt, turn[N], belong[N], vis[N];
void add(int x, int y)
{
    e[++tot].to = y;
    e[tot].next = head_for[x];
    head_for[x] = tot;
    e[++tot].to = x;
    e[tot].next = head_back[y];
    head_back[y] = tot;
}
void dfs1(int u)
{
    int i;
    vis[u] = 1;
    for (i = head_for[u]; i; i = e[i].next)
        if (!vis[e[i].to])
            dfs1(e[i].to);
    turn[++cnt] = u;
}
void dfs2(int u)
{
    belong[u] = cnt;
    vis[u] = 1;
    for (int i = head_back[u]; i; i = e[i].next)
        if (!vis[e[i].to])
            dfs2(e[i].to);
}
void kosaraju()
{
    for (int i = 1; i <= 2 * n; i++)
        if (!vis[i])
            dfs1(i);
    reset(vis);
    cnt = 0;
    for (int i = 2 * n; i >= 1; i--)
        if (!vis[turn[i]])
            cnt++, dfs2(turn[i]);
}

signed main()
{
    ios::sync_with_stdio(false);

    cin >> n >> a >> b;

    for (int i = 1; i <= n; i++)
    {
        cin >> x[i];
    }

    map<int, int> val2id;
    for (int i = 1; i <= n; i++)
    {
        val2id[x[i]] = i;
    }

    for (int i = 1; i <= n; i++)
    {
        if (val2id[a - x[i]])
        {
            add(i, val2id[a - x[i]]);
            add(i + n, n + val2id[a - x[i]]);
        }
        else
        {
            add(i, i + n);
        }
        if (val2id[b - x[i]])
        {
            add(i + n, n + val2id[b - x[i]]);
            add(i, val2id[b - x[i]]);
        }
        else
        {
            add(i + n, i);
        }
        flag = 0;
    }

    kosaraju();

    for (int i = 1; i <= n; i++)
        if (belong[i] == belong[i + n])
        {
            cout << "NO";
            return 0;
        }
    cout << "YES
";
    for (int i = 1; i <= n; i++)
    {
        cout << (belong[i] < belong[i + n]) << ' ';
    }
    return 0;
}
原文地址:https://www.cnblogs.com/mollnn/p/14615917.html