题目:

http://acm.hdu.edu.cn/showproblem.php?pid=2828

题意:

有n盏灯和m个开关,一盏灯可以被很多开关控制,有些开关的开和关是颠倒的,对于一盏灯,只要有一个开关是符合条件的,那么这盏灯就会亮。求一组开关的方案,使所有灯是打开的,并输出方案,不能的话输出-1

思路:

每个开关有开和关两种,所以2*m行n列。因为任一开关的开和关不能并存,所以不能直接套重复覆盖模板,稍微修改以下dance函数,使开和关只能选取一个

#include <bits/stdc++.h>

using namespace std;

const int X = 500000 + 10, N = 1000 + 10, M = 500 + 10, INF = 0x3f3f3f3f;

struct DLX
{
    int U[X], D[X], L[X], R[X], row[X], col[X];
    int H[N], S[M];
    int head, sz, tot, n, m, ans[N];
    bool vis[N];//vis用来标记行,以前的模板标记的是列,切记
    void init(int _n, int _m)
    {
        n = _n, m = _m;
        for(int i = 0; i <= m; i++)
            L[i] = i-1, R[i] = i+1, U[i] = D[i] = i, S[i] = 0;
        head = 0, tot = 0, sz = m;
        L[head] = m, R[m] = head;
        for(int i = 1; i <= n; i++) H[i] = -1;
        memset(vis, 0, sizeof vis);
    }
    void link(int r, int c)
    {
        ++S[col[++sz]=c];
        row[sz] = r;
        D[sz] = D[c], U[D[c]] = sz;
        U[sz] = c, D[c] = sz;
        if(H[r] < 0) H[r] = L[sz] = R[sz] = sz;
        else R[sz] = R[H[r]], L[R[H[r]]] = sz, L[sz] = H[r], R[H[r]] = sz;
    }
    void del(int x)
    {
        for(int i = D[x]; i != x; i = D[i])
            R[L[i]] = R[i], L[R[i]] = L[i];
    }
    void recover(int x)
    {
        for(int i = U[x]; i != x; i = U[i])
            R[L[i]] = L[R[i]] = i;
    }
    int fun_f()
    {
        memset(vis, 0, sizeof vis);
        int num = 0;
        for(int i = R[head]; i != head; i = R[i])
            if(! vis[i])
            {
                vis[i] = true;
                num++;
                for(int j = D[i]; j != i; j = D[j])
                    for(int k = R[j]; k != j; k = R[k])
                        vis[col[k]] = true;
            }
        return num;
    }
    bool dance(int dep)
    {
        if(R[head] == head)
        {
            return true;
        }
        //if(dep-1 + fun_f() > k) return false;//不用估价函数
        int c = R[head];
        for(int i = R[head]; i != head; i = R[i])
            if(S[i] < S[c]) c = i;
        for(int i = D[c]; i != c; i = D[i])
        {
            if(vis[row[i]^1]) continue;
            vis[row[i]] = true;
            del(i);
            for(int j = R[i]; j != i; j = R[j]) del(j);
            if(dance(dep + 1)) return true;
            for(int j = L[i]; j != i; j = L[j]) recover(j);
            recover(i);
            vis[row[i]] = false;
        }
        return false;
    }
}dlx;
int main()
{
    int n, m;
    while(~ scanf("%d%d", &n, &m))
    {
        dlx.init(2 * m + 1, n);
        for(int i = 1; i <= n; i++)
        {
            int k, x;
            char op[10];
            scanf("%d", &k);
            for(int j = 1; j <= k; j++)
            {
                scanf("%d%s", &x, op);
                if(op[1] == 'N') dlx.link((x-1)*2 + 2, i);//为了方便,行号从2开始,所以开2*m+1行
                else dlx.link((x-1)*2 + 3, i);
            }
        }
        bool flag = dlx.dance(1);
        if(flag == false) puts("-1");
        else
        {
            for(int i = 2; i <= 2*m; i += 2)
                printf("%s%c", (dlx.vis[i] == true) ? "ON" : "OFF", i == 2*m ? '\n' : ' ');
        }
    }
    return 0;
}