这题因为建图卡了好久,Dancing Links的入门题,不想多说什么。想了解的请参看Knuth的论文。
这里学会了一个很方便的双向链表插入算法,如果要将x插入到双向链表中,只要先更新x的指针域,然后调用dlx的第二步就可以了。
在init函数有所实现。
我的代码:
using namespace std;
const int nColumn = 1100;
const int nRow = 1100;
const int nNode = nRow*nColumn;
const int head = 0;
const int oo = 0x3f3f3f3f;
int right[nNode], left[nNode], up[nNode], down[nNode];
int cnt[nColumn];
int result[nNode], nResult;
int row[nRow][nColumn], column[nColumn][nRow];
int cntRow[nRow], cntColumn[nColumn];
int nR, nC;
int getColumn(int id) {
if (id % nC)
return id % nC;
else
return nC;
}
int getId(int r, int c) {
return r * nC + c;
}
int getRow(int id) {
return (id - 1) / nC;
}
void remove(const int& x) {
left[right[x]] = left[x];
right[left[x]] = right[x];
for (int r = down[x]; r != x; r = down[r]) {
for (int c = right[r]; c != r; c = right[c]) {
up[down[c]] = up[c];
down[up[c]] = down[c];
cnt[getColumn(c)]--;
}
}
}
void resume(const int& x) {
for (int r = up[x]; r != x; r = up[r]) {
for (int c = left[r]; c != r; c = left[c]) {
cnt[getColumn(c)]++;
up[down[c]] = c;
down[up[c]] = c;
}
}
left[right[x]] = x;
right[left[x]] = x;
}
bool dfs(const int& k) {
if (right[head] == head) {
nResult = k;
return true;
}
int S = oo, x = 0;
for (int t = right[head]; t != head; t = right[t]) {
if (cnt[t] < S) {
S = cnt[t];
x = t;
}
}
remove(x);
for (int r = down[x]; r != x; r = down[r]) {
result[k] = getRow(r);
for (int c = right[r]; c != r; c = right[c]) {
remove(getColumn(c));
}
if (dfs(k + 1))
return true;
for (int c = left[r]; c != r; c = left[c]) {
resume(getColumn(c));
}
}
resume(x);
return false;
}
bool init(int r, int c) {
int id, pre;
//deal with list heads
left[head] = c;
right[head] = 1;
for (int i = 1; i <= c; i++) {
left[i] = i - 1;
right[i] = (i + 1) % (c + 1);
up[i] = down[i] = i;
cnt[i] = cntColumn[i];
if (cnt[i] == 0)
return false;
}
//deal with columns
for (int i = 1; i <= c; i++) {
for (int j = 0; j < cnt[i]; j++) {
id = getId(column[i][j], i);
up[id] = i;
down[id] = down[i];
up[down[id]] = id;
down[up[id]] = id;
left[id] = right[id] = id;
}
}
//deal with rows
for (int i = 1; i <= r; i++) {
for (int j = 1; j < cntRow[i]; j++) {
id = getId(i, row[i][j]);
pre = getId(i, row[i][j - 1]);
left[id] = pre;
right[id] = right[pre];
left[right[id]] = id;
right[left[id]] = id;
}
}
return true;
}
int main() {
int x;
#ifdef DEBUG1
freopen("in.txt", "r", stdin);
#endif
while (~scanf("%d%d", &nR, &nC)) {
for (int i = 1; i <= nC; i++) {
cntColumn[i] = 0;
}
for (int i = 1; i <= nR; i++) {
scanf("%d", &cntRow[i]);
for (int j = 0; j < cntRow[i]; j++) {
scanf("%d", &x);
row[i][j] = x;
column[x][cntColumn[x]++] = i;
}
}
if (!init(nR, nC)) {
puts("NO");
continue;
}
if (!dfs(0)) {
puts("NO");
continue;
}
printf("%d", nResult);
for (int i = 0; i < nResult; i++) {
printf(" %d", result[i]);
}
puts("");
}
return 0;
}