int ok = 0; // n 是行, m 是列 // 枚举每行是否被选 例如,state = 5 对应 101 选第1、3行 for (int state = 0; state < 1 << n; ++state) { int flag = 1; for (int i = 1; i <= n; ++i) { if ((1 << i - 1) & state) {// 当前所选目标行 (对于当前行记录哪些已选) } (和其他行(之前已记录的行)对比看是不是互补) if(冲突了) { flag = 0; break; } } if (!flag) { continue; } else { ok = 1; for (int i = 1; i <= n; ++i) if ((1 << i - 1) & state) printf("%d ", i); puts(""); } } if (!ok) puts("No solution.");
int ok = 0; for (int i = 1; i <= n; ++i) // num[i] 是一个整型数组,表示第 i 行的二进制表示 for (int j = m; j >= 1; --j) num[i] = num[i] << 1 | a[i][j]; // 每次左移一位 (num[i] << 1),然后加上当前列的值 (a[i][j]),最终构成一个二进制数 // 假设 a[i] 为 [1, 0, 1],则 num[i] 最终为 101 for (int state = 0; state < 1 << n; ++state) { int tmp = 0; for (int i = 1; i <= n; ++i) if ((1 << i - 1) & state) { if (tmp & num[i]) break; tmp |= num[i]; } if (tmp == (1 << m) - 1) { ok = 1; for (int i = 1; i <= n; ++i) if ((1 << i - 1) & state) printf("%d ", i); puts(""); } } if (!ok) puts("No solution.");
重复覆盖问题
重复覆盖问题与精确覆盖问题类似,但没有对元素相似性的限制。下文介绍的
X 算法
原本针对精确覆盖问题,但经过一些修改和优化(已标注在其中)同样可以高效地解决重复覆盖问题。
X 算法
Donald E. Knuth 提出了 X 算法 (Algorithm
X),其思想与刚才的暴力差不多,但是方便优化。
voidremove(constint &c){ // 进行remove操作 int i, j; L[R[c]] = L[c], R[L[c]] = R[c]; for (i = D[c]; i != c; i = D[i]) for (j = R[i]; j != i; j = R[j]) U[D[j]] = U[j], D[U[j]] = D[j], --siz[col[j]]; }
voidrecover(constint &c){ // 进行recover操作 int i, j; for (i = U[c]; i != c; i = U[i]) for (j = L[i]; j != i; j = L[j]) U[D[j]] = D[U[j]] = j, ++siz[col[j]]; L[R[c]] = R[L[c]] = c; }
booldance(int dep){ // dance if (!R[0]) { ans = dep; return1; } int i, j, c = R[0]; for (i = R[0]; i != 0; i = R[i]) if (siz[i] < siz[c]) c = i; remove(c); for (i = D[c]; i != c; i = D[i]) { stk[dep] = row[i]; for (j = R[i]; j != i; j = R[j]) remove(col[j]); if (dance(dep + 1)) return1; for (j = L[i]; j != i; j = L[j]) recover(col[j]); } recover(c); return0; } } solver;
intmain(){ n = read(), m = read(); solver.build(n, m); for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) { int x = read(); if (x) solver.insert(i, j); } solver.dance(1); if (ans) for (int i = 1; i < ans; ++i) printf("%d ", stk[i]); else puts("No Solution!"); return0; }