题面很邪恶啊。。。
一对新人请n-1对夫妻吃饭,人们坐在一张桌子的两侧,每一对互为夫妻关系的人必须坐在桌子的两侧。而且有些人两两之间会存在“通奸”关系,通奸关系不仅在男女之间,同性之间也有。新娘对面不可以座有通奸关系的人。判断是否存在可行的排座方案,存在的话输出和新娘同一排的人。
因为新娘对面不可以做有通奸关系的人,也就是说2sat求出的一组可行解是新娘对面的。
如果u和v有通奸关系,就连边u->v',v->u'。
有一点需要注意,就是要连一条边0->1
这样如果选了0就必须选1,那么就矛盾了,所以0一定不被选,选出来的就是新郎那一边的。很巧妙啊!
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std; const int N = ;
const int M = ; struct Edge {
int from, to, next;
} edge[M], edge2[M];
int head[N];
int cntE, cntE2;
void addedge(int u, int v) {
edge[cntE].from = u; edge[cntE].to = v; edge[cntE].next = head[u]; head[u] = cntE++;
}
void addedge2(int u, int v) {
edge2[cntE2].from = u; edge2[cntE2].to = v; edge2[cntE2].next = head[u]; head[u] = cntE2++;
} int dfn[N], low[N], idx;
int stk[N], top;
int in[N];
int kind[N], cnt; void tarjan(int u)
{
dfn[u] = low[u] = ++idx;
in[u] = true;
stk[++top] = u;
for (int i = head[u]; i != -; i = edge[i].next) {
int v = edge[i].to;
if (!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
else if (in[v]) low[u] = min(low[u], dfn[v]);
}
if (low[u] == dfn[u]) {
++cnt;
while () {
int v = stk[top--]; kind[v] = cnt; in[v] = false;
if (v == u) break;
}
}
} int opp[N], ind[N], col[N]; // 相对的点 入度 染色 col[]=1选择 bool topsort(int n) // 序号从0开始
{
for (int i = ; i < *n; i += ) {
int k1 = kind[i]; int k2 = kind[i^]; // 相对的两个的关系
//printf("%d %d %d %d\n", i, i^1, k1, k2);
if (k1 == k2) return false;
opp[k1] = k2; opp[k2] = k1;
}
memset(head, -, sizeof head);
int u, v;
for (int i = ; i < cntE; ++i) {
u = edge[i].from, v = edge[i].to;
if (kind[u] != kind[v]) { // 反向建图
addedge2(kind[v], kind[u]);
ind[kind[u]]++;
}
}
queue<int> q;
for (int i = ; i <= cnt; ++i) if (!ind[i]) q.push(i);
while (q.size()) {
u = q.front(); q.pop();
if (!col[u]) col[u] = , col[ opp[u] ] = -;
for (int i = head[u]; i != -; i = edge2[i].next)
if (--ind[edge2[i].to] == ) q.push(edge2[i].to);
}
return true;
} void init() {
cntE = cntE2 = ;
memset(head, -, sizeof head);
memset(dfn, , sizeof dfn);
memset(in, false, sizeof in);
idx = top = cnt = ;
memset(ind, , sizeof ind);
memset(col, , sizeof col);
} int main() {
int n, m;
int u, v;
while (scanf("%d%d", &n, &m) == ) {
if (n == && m == )break;
init();
while (m--) {
//3h 7h
char s1, s2;
scanf("%d%c%d%c", &u, &s1, &v, &s2);
u = s1=='w' ? u* : u*+;
v = s2=='w' ? v* : v*+;
if (!u || !v) continue;
addedge(u, v^);
addedge(v, u^);
}
addedge(, );
for (int i = ; i < * n; ++i) {
if (!dfn[i]) tarjan(i);
}
if (topsort(n)) {
for (int i = ; i < n; i++) {
if (col[ kind[*i] ] == ) printf("%dh", i);
else printf("%dw", i);
if (i < n - ) printf(" ");
else printf("\n");
}
} else printf("bad luck\n");
}
return ;
}