codeforces 469D 2-SAT

codeforces 469D

题意:
n 个数,给出常数 a、b, 要把这 n 个数分成两个不相交的集合 A、B 。且要满足:
如果某数 x 在 A 里,那么 a-x 也要在 A 里;如果 x 在 B 里,那么 b-x 也要在 B 里。

tags:
把 n 个数看成变量,要么在 A,要么在 B,即二判定性,可用 2-SAT 解。对于数 x, 用点 x2 表示它在 A集合,用点 x2+1 表示它在 B 集合。
但重点是如何连边:
1】如果对 x ,有 a-x 存在,那么就加双向边 [ x2, (a-x)2 ] , [ x2+1, (a-x)2+1 ] 。
表示如果 x 在 A集合,那么 a-x 也要在 A集合; 如 x 在 B 集合,那么 a-x 也要在 B集合。
2】如果对 x, 没有 a-x 存在,那么就加单向边 [ x2, x2+1 ] 。
表示如果推出了 x 在 A 集合,我们要否定这种情况,把它转回到 B 集合来。

//  469 D
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 200005;

int top, Stack[N<<1];
vector< int > G[N<<1];
bool mark[N<<1];
void Addedge(int u, int uval, int v, int vval) {
    u = u*2+uval,  v = v*2+vval;
    G[u].PB(v);
    G[u^1].PB(v^1);
}
bool dfs(int u, int fa)
{
    if(mark[u^1]) return false;
    if(mark[u]) return true;
    mark[u] = true;  Stack[top++] = u;
    for(int to : G[u]) if(!dfs(to, u)) return false;
    return true;
}

int n, a, b;
ll  p[N];
map< ll, int > mp;
int main()
{
    scanf("%d%d%d", &n, &a, &b);
    rep(i,1,n) scanf("%d", &p[i]), mp[p[i]]=i;
    bool flag;
    rep(i,1,n) {
        flag = false;
        if(mp.find(a-p[i])!=mp.end()) Addedge(i, 0, mp[a-p[i]], 0), flag=true;
        else  G[i*2].PB(i*2+1);
        if(mp.find(b-p[i])!=mp.end()) Addedge(i, 1, mp[b-p[i]], 1), flag=true;
        else  G[i*2+1].PB(i*2);
        if(!flag) return printf("NO
"), 0;
    }
    for(int i=2; i<=n*2; i+=2)
    {
        if(mark[i]==false && mark[i^1]==false)
        {
            top = 0;
            if(!dfs(i, 0)) {
                while(top>0) mark[Stack[--top]] = false;
                if(!dfs(i^1, 0)) return printf("NO
"), 0;
            }
        }
    }
    puts("YES");
    for(int i=2; i<=n*2; i+=2)
        if(mark[i]) printf("0 ");
        else  printf("1 ");
    puts("");

    return 0;
}
原文地址:https://www.cnblogs.com/sbfhy/p/8590746.html