题目:
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;
}