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;
}

posted on 2009-11-23 16:08  ZAFU_VA  阅读(337)  评论(0编辑  收藏  举报

导航