参考跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题 - 万仓一黍 - 博客园
2022.5.3补充在网上收集到的一种实现方法,加了自己的部分理解注释,供参考
作者:brealid
链接:https://www.zhihu.com/question/461215932/answer/1903845964
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
bool dance() {
if (!node[0].r) return true;
int minimum_col = node[0].r;//找到该列中1最少的列
for (int i = node[0].r; i != 0; i = node[i].r)
if (siz[i] < siz[minimum_col]) minimum_col = i;
remove(minimum_col);//选择该列
result.push_back(0);//和后面的back()是一个整体操作,先开辟出一个位置,然后存(由于不知道具体存哪一行,所以在后面会不断更新,所以两个操作分开)
for (int i = node[minimum_col].d; i != minimum_col; i = node[i].d) {
result.back() = node[i].row;//在该列中一行一行尝试
for (int j = node[i].l; j != i; j = node[j].l) remove(node[j].col);
if (dance()) return true;//如果本行可以得到解,返回true------------在这里递归了,最后只需要不成功返回false即可,不用再下一列
for (int j = node[i].r; j != i; j = node[j].r) recover(node[j].col);//如果不能,恢复本行,依序下一次循环选该列的下一行
}
result.pop_back();//是对最后一次选择行还不成功进行删除操作
recover(minimum_col);//列不成功,返回false
return false;
}
//行数,列数,最多有几个1(DLX中的1,有很多种意思的)
void init(int row, int col, int count_of_1) {
cnt = col;
first.assign(row + 1, 0);//两种用法,一是将区间[first,last)
的元素复制到当前vector容器中,二是赋n个值为x的元素到vector容器中,这个容器会清除掉vector容器中以前的内容,这里是后者
siz.assign(col + 1, 0);//row+1和col+1是因为有列头节点和行头节点
node.assign(col + count_of_1 + 1, DancingLinksX_Node());//注意是最多有几个1,这里的创建节点只是空节点并且可能还大于后续实际用到的节点数量,注意这里在后面的插入操作的理解
for (int i = 0; i <= col; ++i) {
node[i].l = i - 1;
node[i].r = i + 1;
node[i].u = node[i].d = i;
}
node[0].l = col;//第一个节点的左指针和最后一给节点的右指针的方向 为了形成循环
node[col].r = 0;
}
void insert(int r, int c) {
DancingLinksX_Node &self = node[++cnt];
self.row = r;
self.col = c;
++siz[c];
self.u = node[c].u;
node[self.u].d = cnt;
self.d = c;
node[c].u = cnt;
if (!first[r]) first[r] = self.l = self.r = cnt;///如果是插入第一个节点 (没有左指针,并且该第一个节点自我循环了)行头节点是不参与循环的,只是为了方便指示该行的第一个节点
else {
self.l = node[first[r]].l;//如果是加入到末尾,则当前节点的左指针指向之前的最右节点,那么借助first[r]方便找到
self.r = first[r];
node[node[first[r]].l].r = cnt;
node[first[r]].l = cnt;
}
//for (int j = node[first[r]].l; j != first[r]; j = node[j].l);
//for (int j = node[first[r]].r; j != first[r]; j = node[j].r);
//for (int j = node[cnt].l; j != cnt; j = node[j].l);
//for (int j = node[cnt].r; j != cnt; j = node[j].r);
}