xqz出的一套题中的一个,没想到是搜索……
一开始不敢写,后来看到何天扬的比std快,他用的是dancing links。为了一探究竟,我也来看看这神奇的dancing links。
看了秋哥面前小菜的Knuth的原文,历经千辛万苦,经历艰难险阻,看了杂七杂八的源码,最后终于写出一个dancing links了……
第一次测,只过了两个点,其余全部tle。一查,发现循环写错了,导致全部死循环……
改了之后,重新测,秒了std……
std用的是IDA*,一开始时用了3.34s,加了启发式函数果然快……瞬间降至0.39s!看来如果不写dancing links,启发式还是要写的。
但是,我的dancing links如果加了启发式,那么,速度0.25s!不愧是knuth!
P.S 这个题刷新了我用for的记录,以前是由APIO的oil保持,22个for,现在升级为26个for!
原题:
MR.J的地毯
【问题描述】
MR.J刚刚买了一套房子,但有点小瑕疵:有一些地板不美观。于是,他想买一些地毯把不美观的地板遮起来。地毯必须把所有有瑕疵的地板遮起来,而不能遮到没有瑕疵的地板,地毯可以重复覆盖。具体来说,现在有一个n*m的01矩阵,如果某个位置是1,则代表它要被覆盖,否则不能被覆盖。请你用最少个数的正方形覆盖所有的1,可以重复覆盖。
【输入格式】
输入包括多组数据,以一组0 0结束。
每组数据的第一行为正整数m,n
接下来一个n*m的01矩阵
【输出格式】
对于每组数据,输出最少正方形个数。
【样例输入】
4 3
0 1 1 1
1 1 1 1
1 1 1 1
8 5
0 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 0 1 1 1 1
0 1 1 1 0 1 1 1
0 0
【样例输出】
2
6
【数据说明】
30%:N,M<=10
100%:N,M<=20.数据组数<=5.
#include #include #define maxn 20 #define maxnode 160400 #define maxcol 400 #define oo 0x3F3F3F3F int map[maxn + 3][maxn + 3]; int sum[maxn + 3][maxn + 3]; int ext[maxn + 3][maxn + 3]; int rep[maxn + 3][maxn + 3]; int n, m, t; int L[maxnode + 3]; int R[maxnode + 3]; int U[maxnode + 3]; int D[maxnode + 3]; int C[maxnode + 3]; int size[maxcol + 3]; int hash[maxnode + 3]; int ans; int extend(int x, int y) { int i, j, k = 1; if (!map[x][y]) rep[x][y] = ++t; for (--x, --y; (i = x + k) <= m && (j = y + k) <= n; ++k) if (sum[i][j] + sum[x][y] != sum[i][y] + sum[x][j]) break; ext[x + 1][y + 1] = k - 1; } void cover(int c) { int i; for (i = D[c]; i != c; i = D[i]) L[R[i]] = L[i], R[L[i]] = R[i], size[C[c]]--; } int resume(int c) { int i; for (i = U[c]; i != c; i = U[i]) L[R[i]] = i, R[L[i]] = i, size[C[c]]++; } int eval() { static int timestamp = 0, ret, i, j, c; for (c = R[0], ++timestamp, ret = 0; c != 0; c = R[c]) if (hash[c] != timestamp) { hash[c] = timestamp; ret++; for (i = D[c]; i != c; i = D[i]) for (j = R[i]; j != i; j = R[j]) hash[C[j]] = timestamp; } return ret; } int dancing(int depth) { if (depth + eval() > ans) return 0; if (R[0] == 0) { if (depth < ans) ans = depth; return 0; } int min = R[0], c, i; for (c = R[min]; c != 0; c = R[c]) if (size[c] < size[min]) min = c; for (c = D[min]; c != min; c = D[i]) { cover(c); for (i = R[c]; i != c; i = R[i]) cover(i); dancing(depth + 1); for (i = L[c]; i != c; i = L[i]) resume(i); resume(c); } } int link(int *A, int *B, int u, int v) { A[v] = A[u], B[v] = u, B[A[v]] = v, A[B[v]] = v; } int main(int argc, char *argv[]) { FILE *fin = fopen("input.txt", "r"); FILE *fout = fopen("output.txt", "w"); int i, j, k, x, y, now; for (; fscanf(fin, "%d%d", &n, &m) && n && m; ) { t = 0, k = 0, ans = oo; for (i = 1; i <= m; ++i) //reading for (j = 1; j <= n; ++j) fscanf(fin, "%d", &map[i][j]), map[i][j] = !map[i][j]; for (i = 1; i <= m; ++i) //get sum for (j = 1; j <= n; ++j) sum[i][j] = map[i][j] - sum[i - 1][j - 1] + sum[i][j - 1] + sum[i - 1][j]; for (i = 1; i <= m; ++i) //get ext for (j = 1; j <= n; ++j) extend(i, j); for (i = 1; i <= m; ++i) //delete some mat for (j = 1; j <= n; ++j) if (!map[i][j]) for (x = i; x <= m; ++x) for (y = j; y <= n; ++y) if ((x != i || y != j) && i + ext[i][j] >= x + ext[x][y] && j + ext[i][j] >= y + ext[x][y]) ext[x][y] = 0; for (i = 0; i <= t; ++i) C[i] = U[i] = D[i] = i, R[i] = i + 1, L[i] = i - 1, size[i] = 0; R[t] = 0, L[0] = t; for (i = 1, k = t; i <= m; ++i) for (j = 1; j <= n; ++j) if (ext[i][j]) { ++k, now = L[k] = R[k] = k, C[k] = rep[i][j]; link(U, D, C[k], k), size[C[k]]++; for (x = 0; x < ext[i][j]; ++x) for (y = 0; y < ext[i][j]; ++y) if (x || y) { C[++k] = rep[i + x][j + y]; link(U, D, C[k], k), size[C[k]]++; link(L, R, now, k); } } ans = oo, dancing(0); fprintf(fout, "%d/n", ans); } fclose(fin); fclose(fout); return 0; }