pku 1084 重复覆盖问题
#include <iostream>
#include <cmath>
using namespace std;
const int N = 5;
const int MAXN = 2*N*(N+1);
const int MAXM = N*(N+1)*(2*N+1)/6;
const int MAXC = MAXM*MAXN;
const int MAXSTEP[6] = {0,1,3,6,9,9};
typedef __int64 ULL;
int L[MAXC], R[MAXC], U[MAXC], D[MAXC];
int ROW[MAXC], COL[MAXC];
int hashRow[MAXN], hashCol[MAXM];
int lenCol[MAXM];
int head, eid, cn, ans, n;
bool hash[MAXM], flag[MAXN];
int up[N][N];
int box[MAXM][N*4];
ULL cover[MAXM]; //小方块包含哪些sticks 如果构不成则为0
int a[64]; //将cover以二进制输出 用于调试
void init()
{
memset(ROW, -1, sizeof(ROW));
memset(COL, -1, sizeof(COL));
memset(hashRow, -1, sizeof(hashRow));
memset(hashCol, -1, sizeof(hashCol));
head = 0, eid = 1, cn = 0;
L[head] = R[head] = U[head] = D[head] = head;
}
void insRow(int r)
{
U[D[head]] = eid;
U[eid] = head;
D[eid] = D[head];
D[head] = eid;
L[eid] = R[eid] = eid;
hashRow[r] = eid++;
}
void insCol(int c)
{
L[R[head]] = eid;
L[eid] = head;
R[eid] = R[head];
R[head] = eid;
U[eid] = D[eid] = eid;
hashCol[c] = eid++;
lenCol[c] = 1;
}
void insElement(int r, int c)
{
int rid = hashRow[r], cid = hashCol[c];
U[D[cid]] = eid;
U[eid] = cid;
D[eid] = D[cid];
D[cid] = eid;
L[R[rid]] = eid;
L[eid] = rid;
R[eid] = R[rid];
R[rid] = eid;
ROW[eid] = r, COL[eid++] = c;
lenCol[c]++;
}
void insert(int r, int c)
{
if (hashCol[c] == -1)
{
insCol(c);
++cn;
}
if (hashRow[r] == -1)
{
insRow(r);
}
insElement(r, c);
}
void RemoveCol(int cid)
{
int i;
for (i = D[cid]; i != cid; i = D[i])
{
L[R[i]] = L[i];
R[L[i]] = R[i];
}
}
void ResumeCol(int cid)
{
int i;
for (i = U[cid]; i != cid; i = U[i])
{
L[R[i]] = i;
R[L[i]] = i;
}
}
int AStar()
{
int ret = 0;
memset(hash, 0, sizeof(hash));
int i, j, k;
for (i = R[head]; i != head; i = R[i])
{
if (COL[D[i]] != -1 && !hash[COL[D[i]]])
{
ret++;
hash[COL[D[i]]] = true;
for (j = D[i]; j != i; j = D[j])
{
if (COL[j] != -1)
{
for (k = R[j]; k != j; k = R[k])
{
if (COL[k] != -1)
{
hash[COL[k]] = true;
}
}
}
}
}
}
return ret;
}
void debug(ULL v)
{
int i = 0, j;
while (v!=0)
{
a[i++]=int(v%2);
v=v/2;
}
for(j=i-1;j>=0;j--)
{
printf("%d",a[j]);
}
printf("\n");
}
void dfs(int k)
{
if (k + AStar() > MAXSTEP[n])
{
return;
}
if (R[head] == head)
{
if (k < ans)
{
ans = k;
}
return;
}
int MIN = INT_MAX, c;
int i, j;
for (i = R[head]; i != head; i = R[i])
{
if (COL[D[i]] == -1)
{
c = i;
continue;
}
if (lenCol[COL[D[i]]] < MIN)
{
c = i;
MIN = lenCol[COL[D[i]]];
}
}
for (i = D[c]; i != c; i = D[i])
{
RemoveCol(i);
for (j = R[i]; j != i; j = R[j])
{
if (COL[j] != -1)
{
RemoveCol(j);
}
}
dfs(k+1);
for (j = L[i]; j != i; j = L[j])
{
if (COL[j] != -1)
{
ResumeCol(j);
}
}
ResumeCol(i);
}
}
void solution()
{
init();
int p;
scanf("%d %d", &n, &p);
int i, j, k, q;
ans = 9;
memset(flag, 1, sizeof(flag));
for (i = 0; i < p; ++i)
{
int a;
scanf("%d", &a);
flag[a-1] = false;
}
int pos = 0;
for (i = 0; i < n; ++i)
{
up[i][0] = i * (2 * n + 1);
for (j = 1; j < n; ++j)
{
up[i][j] = up[i][j-1] + 1;
}
}
memset(box, -1, sizeof(box));
for (i = 1; i <= n; ++i)
{
for (j = 0; j <= n - i; ++j)
{
for (k = 0; k <= n - i; ++k)
{
for (q = 0; q < i; ++q)
{
box[pos][q] = up[j][k+q];
}
for (q = i; q < 2*i; ++q)
{
box[pos][q] = up[j][k]+n+(q-i)*(2*n+1);
}
for (q = 2*i; q < 3*i; ++q)
{
box[pos][q] = up[j][k+i-1]+n+1+(q-2*i)*(2*n+1);
}
for (q = 3*i; q < 4*i; ++q)
{
box[pos][q] = up[j][k]+n+(i-1)*(2*n+1)+n+1+q-3*i;
}
pos++;
}
}
}
//for (i = 0; i < n*(n+1)*(2*n+1)/6; ++i)
//{
// for (j = 0; j < 4*n; ++j)
// {
// if (box[i][j] == -1)
// {
// break;
// }
// printf("%d ", box[i][j]);
// }
// puts("");
//}
for (i = 0; i < n*(n+1)*(2*n+1)/6; ++i)
{
cover[i] = 0;
for (j = 0; j < 4*n; ++j)
{
if (box[i][j] == -1)
{
break;
}
if (!flag[box[i][j]])
{
cover[i] = 0;
break;
}
else
{
cover[i] |= (ULL(1) << box[i][j]); //ULL(1)
}
}
}
//for (i = 0; i < n*(n+1)*(2*n+1)/6; ++i)
//{
// printf("%d ", i);
// debug(cover[i]);
//}
for (i = 0; i < 2*n*(n+1); ++i)
{
for (j = 0; j < n*(n+1)*(2*n+1)/6; ++j)
{
if (cover[j] & (ULL(1) << i)) //这里也是 杯具了好几次
{
insert(i, j);
}
}
}
dfs(0);
printf("%d\n", ans);
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
solution();
}
return 0;
}