====== DLX(Dancing Links X 舞蹈链) ====== ===== 简介 ===== 求解精准覆盖问题:给定一个集合和若干个子集,选择若干个子集使得原集合中每一个元素出现且仅出现一次。 ===== 思路 ===== 用矩阵的方式存储子集:每一行代表一个子集,每一列代表原集合中的一个元素,某行某列用0和1代表这一个子集是否含有这一个元素。 1. 对于一个存在1的列找一个行\\ 2. 删除该行、行上点的所在列、包含行上点所在列的行$\to$1.\\ 3. 余下列但无可用行$\to$回溯\\ 4. 不余——输出答案/储存答案\\ ==== 实现方法 ==== 利用十字循环链表。 === 初始化 === void init() { cnt=m; for(int i=0;i<=m;i++) node[i]={i,i,i-1,i+1,0,i}; node[m].d=0; node[0].a=m; } === 添加点 === for(int i=1;i<=n;i++) for(int j=1,a;j<=m;j++) { scanf("%d",&a); if(a) { tot[j]++; node[++cnt]={node[j].w,j,0,0,i,j}; node[node[j].w].s=cnt; node[j].w=cnt; if(!left[i]) left[i]=node[cnt].a=node[cnt].d=cnt; else { node[cnt].d=left[i]; node[cnt].a=node[left[i]].a; node[node[left[i]].a].d=cnt; node[left[i]].a=cnt; } } } === 删除列 === void remove(int x) { node[node[x].a].d=node[x].d; node[node[x].d].a=node[x].a; for(int i=node[x].s;i!=x;i=node[i].s) for(int j=node[i].d;j!=i;j=node[j].d) { node[node[j].w].s=node[j].s; node[node[j].s].w=node[j].w; tot[node[j].c]--; } } === 恢复列 === void recover(int x) { for(int i=node[x].w;i!=x;i=node[i].w) for(int j=node[i].d;j!=i;j=node[j].d) { node[node[j].w].s=node[node[j].s].w=j; tot[node[j].c]++; } node[node[x].a].d=node[node[x].d].a=x; } === X主体 === bool dlx(int dep) { if(!node[0].d) { for(int i=1;i 注:恢复列时要从删除列的最后一个开始恢复。 ===== 例题 ===== ==== 【模板】舞蹈链(DLX) ==== **来源**:洛谷p4929 **概述**:模板 **答案**:模板 #include using namespace std; int n,m,cnt,left[505],ans[505],tot[505]; struct unit{int w,s,a,d,r,c;}node[6000]; void init() { cnt=m; for(int i=0;i<=m;i++) node[i]={i,i,i-1,i+1,0,i}; node[m].d=0; node[0].a=m; } void remove(int x) { node[node[x].a].d=node[x].d; node[node[x].d].a=node[x].a; for(int i=node[x].s;i!=x;i=node[i].s) for(int j=node[i].d;j!=i;j=node[j].d) { node[node[j].w].s=node[j].s; node[node[j].s].w=node[j].w; tot[node[j].c]--; } } void recover(int x) { for(int i=node[x].w;i!=x;i=node[i].w) for(int j=node[i].d;j!=i;j=node[j].d) { node[node[j].w].s=node[node[j].s].w=j; tot[node[j].c]++; } node[node[x].a].d=node[node[x].d].a=x; } bool dlx(int dep) { if(!node[0].d) { for(int i=1;i ---- ===== 总结 =====