题意
传送门 POJ 3648 Wedding
题解
定义布尔变量 x i x_i xi
x i 为 真 ⇔ 参 与 者 i 位 于 新 娘 座 位 一 侧 x_i为真\Leftrightarrow 参与者i位于新娘座位一侧 xi为真⇔参与者i位于新娘座位一侧 则对于每一对夫妻 i , j i,j i,j,都有 ¬ ( x i ∧ x j ) ∨ ( ¬ x i ∧ ¬ x j ) ) \lnot (x_i\land x_j)\lor (\lnot x_i\land \lnot x_j)) ¬(xi∧xj)∨(¬xi∧¬xj));对于每一对不能同时出现在新娘对侧的组合 i , j i,j i,j,都有 ¬ ( ¬ x i ∧ ¬ x j ) \lnot(\lnot x_i\land \lnot x_j) ¬(¬xi∧¬xj);对于新娘、新郎 i , j i,j i,j,则有 x i = 1 , x j = 0 x_i=1,x_j=0 xi=1,xj=0。建图,使用 T a r j a n Tarjan Tarjan 算法求解 2 − S A T 2-SAT 2−SAT,总时间复杂度 O ( N 2 ) O(N^2) O(N2)。
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 35, maxv = maxn * 4, maxe = 4 * (4 * maxn * maxn + maxn);
int N, P, res[maxn * 2];
int tot, head[maxv], to[maxe], nxt[maxe];
int num, dfn[maxv], low[maxv];
int top, st[maxv], scc, sc[maxv];
bool ins[maxv];
inline void add(int x, int y) {
to[++tot] = y, nxt[tot] = head[x], head[x] = tot; }
void tarjan(int x)
{
low[x] = dfn[x] = ++num;
st[++top] = x, ins[x] = 1;
for (int i = head[x]; i; i = nxt[i])
{
int y = to[i];
if (!dfn[y])
tarjan(y), low[x] = min(low[x], low[y]);
else if (ins[y])
low[x] = min(low[x], dfn[y]);
}
if (low[x] == dfn[x])
{
++scc;
int y;
do
{
y = st[top--], ins[y] = 0, sc[y] = scc;
} while (y != x);
}
}
int main()
{
while (~scanf("%d%d", &N, &P) && (N | P))
{
tot = num = top = scc = 0;
memset(head, 0, sizeof(head)), memset(dfn, 0, sizeof(dfn));
memset(sc, 0, sizeof(sc)), memset(ins, 0, sizeof(ins));
int n2 = N * 2, lim = N * 4;
for (int i = 1, x, y; i <= P; ++i)
{
char a, b;
scanf("%d%c%d%c", &x, &a, &y, &b);
++x, ++y;
if (a == 'w')
x += N;
if (b == 'w')
y += N;
add(n2 + x, y), add(n2 + y, x);
}
add(n2 + N + 1, N + 1), add(1, n2 + 1);
for (int i = 2; i <= N; ++i)
{
int x = i, y = N + i;
add(x, n2 + y), add(y, n2 + x), add(n2 + x, y), add(n2 + y, x);
}
for (int i = 1; i <= lim; ++i)
if (!dfn[i])
tarjan(i);
bool f = 1;
for (int i = 1; i <= n2; ++i)
if (sc[i] == sc[n2 + i])
{
puts("bad luck");
f = 0;
break;
}
if (f)
{
int k = 0;
for (int i = 1; i <= n2; ++i)
if (sc[i] < sc[n2 + i] && i != N + 1)
res[++k] = i;
while (k)
(res[k] <= N) ? printf("%dh ", res[k] - 1) : printf("%dw ", res[k] - N - 1), --k;
putchar('\n');
}
}
return 0;
}