POJ 3648 2-SAT

题意

传送门 POJ 3648 Wedding

题解

定义布尔变量 x i x_i xi
x i 为 真 ⇔ 参 与 者 i 位 于 新 娘 座 位 一 侧 x_i为真\Leftrightarrow 参与者i位于新娘座位一侧 xii 则对于每一对夫妻 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)) ¬(xixj)(¬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 2SAT,总时间复杂度 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;
}

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/115272817