给n个互不相等的整数,要把他们分成两个集合。如果x属于集合A,那么a-x也要属于;如果x属于集合B,那么b-x也要属于。问能不能找到这样的解,有解的话输出解。如果第i个元素属于A,输出0;如果属于B输出1.
http://codeforces.com/problemset/problem/468/B
好久不做2-SAT。。。。
首先,这n个数都是互不相同的。也就是说,对于每个数x,最多有一个y,使得x + y = a;同样最多有一个z,使得x + z = b。
如果y和z都不存在,那就一定无解,直接输出“NO”。
如果z不存在y存在,那么就说明x和y一定属于一个集合。我们连边mp[x]--mp[y], mp[x]'--mp[y]',这里mp[i] = 值为i的元素编号。
y不存在z存在也是一样的。
那么y和z要是都存在呢?x和y一个集合,或者x和z一个集合。这有3个点可怎么连边~~o(>_<)o ~~
想一想。。。。。
发现y和z不能属于同一集合,也就是他们之间存在异或关系。连mp[y]'--mp[z],mp[y]--mp[z]'.
好像顺利解决了。。!
。。。突然发现如果y或者z = x,这样连边就矛盾了。+_+
嗯。。。矛盾了无非就是u连了v又连了v'。。。就是u可以和v一个集合,也可以不和v一个集合。。。。相当于废话。直接不连就好了。。!
然后就是要输出解。。。
2-sat输出路径实在好麻烦。。又是缩点啊,又是拓扑排序啊,又是染色啊。。。。。
直接判断x,y,z的id,x和y一样就输出0,和z一样就输出1.当然还要考虑y或z和x相等的情况。
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef double DB;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
#define pb push_back
#define MP make_pair
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
const DB eps = 1e-8;
const int inf = 0x3f3f3f3f;
const int mod = 10000007;
const int maxn = 200000 + 10;
int n, a, b, p[maxn];
map<int, int> mp;
map<int, int> ::iterator it;
struct node{
int v, next;
}edge[2000000];
int head[maxn], cnt, dfn[maxn], low[maxn], used[maxn], id[maxn], sz, idx;
stack<int> sta;
void addedge(int u, int v){
edge[cnt].v = v; edge[cnt].next = head[u]; head[u] = cnt++;
//cout <<"u:" << u << ", v:" << v <<endl;
}
void Tarjan(int x){
dfn[x] = low[x] = ++idx;
sta.push(x);
used[x] = 1;
for(int i=head[x]; ~i; i=edge[i].next){
int k = edge[i].v;
if(!dfn[k]){
Tarjan(k);
low[x] = min(low[x], low[k]);
}else if(used[k]) low[x] = min(dfn[k], low[x]);
}
if(dfn[x] == low[x]){
sz++;
int k;
do{
k = sta.top(); sta.pop();
used[k] = 0;
id[k] = sz;
}while(k != x);
}
}
bool Two_SAT(){
idx = sz = 0;
memset(dfn, 0, sizeof(dfn));
while(!sta.empty()) sta.pop();
for(int i=0; i<2*n; i++)
if(!dfn[i]) Tarjan(i);
// for(int i=0; i<2*n; i++)
// printf("%d %d\n", i, id[i]);
for(int i=0; i<n; i++)
if(id[i] == id[i + n]) return false;
return true;
}
bool cal(){
for(int i=0; i<n; i++){
int cnt = 0, y = a - p[i], z = b - p[i];
if((it = mp.find(y)) != mp.end()){
cnt |= 1;
}
if((it = mp.find(z)) != mp.end()){
cnt |= 2;
}
if(!cnt)return false;
if(cnt == 1){///x&y
if(p[i] != y) {addedge(i, mp[y]); addedge(mp[y], i); addedge(i + n, mp[y] + n); addedge(mp[y] + n, i + n);}
}else if(cnt == 2){///x&z
if(p[i] != z) {addedge(i, mp[z]); addedge(mp[z], i); addedge(i + n, mp[z] + n); addedge(mp[z] + n, i + n);}
}else if(y == z){///x&y
if(p[i] != y) {addedge(i, mp[y]); addedge(mp[y], i); addedge(i + n, mp[y] + n); addedge(mp[y] + n, i + n);}
}else if(y != p[i] && z != p[i]){///y^z
int yy = mp[y], zz = mp[z];
addedge(yy, zz + n); addedge(zz, yy + n); addedge(yy + n, zz); addedge(zz + n, yy);
}
}
if(!Two_SAT()) return false;
return true;
}
int main(){
while(scanf("%d%d%d", &n, &a, &b) == 3){
mp.clear();
memset(head, -1, sizeof(head)); cnt = 0;
for(int i=0; i<n; i++){
scanf("%d", &p[i]);
mp[p[i]] = i;
}
if(!cal()) {puts("NO"); continue;}
else puts("YES");
for(int i=0; i<n; i++){
int y = a - p[i], z = b - p[i], flag = 0;
if((it = mp.find(y)) != mp.end()){
flag |= 1;
}
if((it = mp.find(z)) != mp.end()){
flag |= 2;
}
if(flag == 1) printf("0 ");
else if(flag == 2) printf("1 ");
else if(p[i] == y && id[i] == id[mp[z]]) printf("1 ");
else if(p[i] == z && id[i] == id[mp[y]]) printf("0 ");
else{
if(id[i] == id[mp[z]]) printf("1 ");
else printf("0 ");
}
}
puts("");
}
return 0;
}