dfs硬怼通过数独 N皇后的代码后 想学习下新的数据结构和算法来解决这类覆盖问题

习题练习

https://www.acwing.com/problem/content/168/ 数独

https://www.acwing.com/problem/content/171/ 数独2

https://www.acwing.com/problem/content/185/ 靶形数独

资料收集如下 进行学习

https://www.cnblogs.com/ivan-count/p/7355431.html

https://www.cnblogs.com/grenet/p/3145800.html

https://blog.csdn.net/whereisherofrom/article/details/79220897

习题学习

洛谷

https://www.luogu.org/problem/P4929  P4929 【模板】舞蹈链(DLX)

https://www.luogu.org/problem/P1074  P1074 靶形数独

https://www.luogu.org/problem/P1219  P1219 八皇后

题解

https://www.luogu.org/blog/ONE-PIECE/qian-tan-dlx  【模板】舞蹈链(DLX)

https://www.luogu.org/blog/ONE-PIECE/ba-xing-shuo-du-dai-ma  靶形数独

https://www.luogu.org/blog/ONE-PIECE/solution-p1219 八皇后

我的对模板注释的代码  参考的源代码地址https://www.luogu.org/blog/ONE-PIECE/qian-tan-dlx

 #include <iostream>
#include <stdio.h>
#include <string.h> //精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1
const int MN = * * + ;//最大行数,共有9*9个格子,每个格子可以放1~9
const int MM = * + * + * + * + ;//最大列数
const int MAX_NUM = MN * MM; //最大点数 struct DLX
{
int n, m, idx;//n行数m列数idx 元素索引
//十字链表组成部分 int l[MAX_NUM], r[MAX_NUM], u[MAX_NUM], d[MAX_NUM]; //记录某个idx索引点的上下左右点的索引
int col[MAX_NUM], row[MAX_NUM]; //两者结合使用 记录某个idx索引点的行 列号 int nodeIdxPerRow[MAX_NUM]; //记录每行的开头节点的索引
int nodeNumPerCol[MAX_NUM]; //记录每列节点的个数 int ansd, ans[MN]; void init(int n ,int m) //初始化十字链表的 头节点和 列节点表头串 m表示有多少列
{
//初始化头结点和 列节点表头串 头节点数组索引 = 0 列节点表头共m个 索引 1~m
for (int i = ; i <= m; i++) {
r[i] = i + ;
l[i] = i - ;
u[i] = d[i] = i; //列节点头串只有互相横向连接 上下连接均指向自己
}
r[m] = ;
l[] = m; //循环连接 col[m] 的右端指向头节点 头结点的左端指向clo[m] memset(nodeIdxPerRow, , sizeof(nodeIdxPerRow));
memset(nodeNumPerCol, , sizeof(nodeNumPerCol)); idx = m + ; //目前使用 0 头结点 与 m个列节点表头串 0~m 共m+1个节点
} //插入节点 进行的一些数据记录
void link(int insertRow, int insertCol)
{
nodeNumPerCol[insertCol]++; //插入一个节点 那么该列的节点个数+1
row[idx] = insertRow;
col[idx] = insertCol; //记录第idx个节点所在的行与列 u[idx] = insertCol; //当前插入的节点索引记录 向上指向列节点头串中的insertCol
d[idx] = d[insertCol]; //当前插入节点索引记录 向下指向原来列节点头串的向下指向点
u[d[insertCol]] = idx; //原来列节点头串指向的节点 向上由指向列节点头串指向插入的节点(使用索引)
d[insertCol] = idx; //列节点头串则向下指向新插入的节点(使用索引) //更新每行的节点记录 nodeIdxPerRow
if (nodeIdxPerRow[insertRow] == ) {
//如果该节点是第一个插入的节点
nodeIdxPerRow[insertRow] = r[idx] = l[idx] = idx;//该行没有点,直接加入
}
else {
//如果不是第一个插入的节点 同上面处理列次序一样 在记录和第一个节点间 插入本函数插入的节点
r[idx] = nodeIdxPerRow[insertRow]; //新节点的右端指向原来行记录中的第一个节点
l[idx] = l[nodeIdxPerRow[insertRow]]; //新节点的左端指向原来行记录第一个节点的左端 也就是行记录nodeIdxPerRow
r[l[nodeIdxPerRow[insertRow]]] = idx; //原来行记录第一个节点的左端(也就是行记录nodeIdxPerRow)的右端 指向新插入的点(使用索引)
l[nodeIdxPerRow[insertRow]] = idx; //原来行记录第一个节点的左端指向新插入的节点(使用索引) }
idx++;
return;
} void remove(int deleteCol) {//删除涉及C列的集合
//将要删除的列的左右两端连接起来 也等于将自己摘除出来
r[l[deleteCol]] = r[deleteCol], l[r[deleteCol]] = l[deleteCol];
for (int i = d[deleteCol]; i != deleteCol; i = d[i]) {
for (int j = r[i]; j != i; j = r[j]) {
u[d[j]] = u[j];
d[u[j]] = d[j];
nodeNumPerCol[col[j]]--;
}
}
}
void resume(int resCol) {//恢复涉及C列的集合
for (int i = u[resCol]; i != resCol; i = u[i]) {
for (int j = l[i]; j != i; j = l[j]) {
u[d[j]] = j;
d[u[j]] = j;
nodeNumPerCol[col[j]]++;
}
}
r[l[resCol]] = resCol;
l[r[resCol]] = resCol;
} bool dance(int deep) //选取了d行
{
if (r[] == )//全部覆盖了
{
//全覆盖了之后的操作
ansd = deep;
return ;
} int c = r[];//表头结点指向的第一个列
for (int i = r[]; i != ; i = r[i])//枚举列头指针
{
if (nodeNumPerCol[i] < nodeNumPerCol[c])c = i; } remove(c);//将该列删去
for (int i = d[c]; i != c; i = d[i])
{//枚举该列的元素
ans[deep] = row[i];//记录该列元素的行
for (int j = r[i]; j != i; j = r[j])
remove(col[j]);//将该列的某个元素的行上的元素所在的列都删去
if (dance(deep + ))
return ;
for (int j = l[i]; j != i; j = l[j])
resume(col[j]);
}
resume(c);
return ;
}
}dlx;
//========================================================== char s[], path[];
struct node
{
int r, c, v;
}nds[MN];
int main()
{
while (~scanf("%s", s))
{
if (s[] == 'e')break;
dlx.init( * * , * * );
int r = ;
for (int i = ; i <= ; i++)
{
for (int j = ; j <= ; j++)
{
if (s[(i - ) * + j - ] == '.')
{
for (int z = ; z <= ; z++)
{
dlx.link(r, (i - ) * + j);
dlx.link(r, + (i - ) * + z);
dlx.link(r, + (j - ) * + z);
dlx.link(r, + (((i - ) / ) * + (j + ) / - ) * + z);
nds[r].r = i, nds[r].c = j, nds[r].v = z;
r++;
}
}
else
{
int z = s[(i - ) * + j - ] - '';
dlx.link(r, (i - ) * + j);
dlx.link(r, + (i - ) * + z);
dlx.link(r, + (j - ) * + z);
dlx.link(r, + (((i - ) / ) * + (j + ) / - ) * + z);
nds[r].r = i, nds[r].c = j, nds[r].v = z;
r++;
}
}
}
dlx.ansd = -;
dlx.dance();
int deep = dlx.ansd;
for (int i = ; i < deep; i++)
{
int posr = dlx.ans[i];
path[(nds[posr].r - ) * + nds[posr].c - ] = '' + nds[posr].v;
}
path[deep] = '\0';
printf("%s\n", path);
}
return ;
}

166. 数独 dancing links 方法的更多相关文章

  1. 算法实践——舞蹈链(Dancing Links)算法求解数独

    在“跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题”一文中介绍了舞蹈链(Dancing Links)算法求解精确覆盖问题. 本文介绍该算法的实际运用,利用舞蹈链(Dancin ...

  2. 转载 - 算法实践——舞蹈链(Dancing Links)算法求解数独

    出处:http://www.cnblogs.com/grenet/p/3163550.html 在“跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题”一文中介绍了舞蹈链(Dan ...

  3. hihoCoder #1321 : 搜索五•数独 (Dancing Links ,精确覆盖)

    hiho一下第102周的题目. 原题地址:http://hihocoder.com/problemset/problem/1321 题意:输入一个9*9数独矩阵,0表示没填的空位,输出这个数独的答案. ...

  4. HDU 1426 dancing links解决数独问题

    题目大意: 这是一个最简单的数独填充题目,题目保证只能产生一种数独,所以这里的初始9宫格较为稠密,可以直接dfs也没有问题 但最近练习dancing links,这类数据结构解决数独无疑效率会高很多 ...

  5. Dancing Links and Exact Cover

    1. Exact Cover Problem DLX是用来解决精确覆盖问题行之有效的算法. 在讲解DLX之前,我们先了解一下什么是精确覆盖问题(Exact Cover Problem)? 1.1 Po ...

  6. 算法帖——用舞蹈链算法(Dancing Links)求解俄罗斯方块覆盖问题

    问题的提出:如下图,用13块俄罗斯方块覆盖8*8的正方形.如何用计算机求解? 解决这类问题的方法不一而足,然而核心思想都是穷举法,不同的方法仅仅是对穷举法进行了优化 用13块不同形状的俄罗斯方块(每个 ...

  7. 浅入 dancing links x(舞蹈链算法)

    abastract:利用dancing links 解决精确覆盖问题,例如数独,n皇后问题:以及重复覆盖问题. 要学习dacning links 算法,首先要先了解该算法适用的问题,精确覆盖问题和重复 ...

  8. Dancing Links X 学习笔记

    \(\\\) Definitions 双向链表:记录前后两个指针的链表,每个顺序关系都有双向的指针维护. \(Dancing\ Links\):双向十字循环链表,建立在二维关系上,每个元素记录上下左右 ...

  9. HUST 1017 - Exact cover (Dancing Links 模板题)

    1017 - Exact cover 时间限制:15秒 内存限制:128兆 自定评测 5584 次提交 2975 次通过 题目描述 There is an N*M matrix with only 0 ...

随机推荐

  1. GC与内存分配策略

    一.GC 第一步:判断对象是否已死?有两种方法:第一种是引用计数法,即给对象添加一个引用计数器,当被引用时,计数器就+1:当引用失效时,就-1:当计数器为0时,代表对象没有被引用.但是计数器的缺点就是 ...

  2. 3.Ansible varialbes实战

    varialbes 1.什么是变量? ​ 以一个固定的字符串,表示一个不固定的值 version: 1.12 2.定义变量? 1.在playbook中定义变量? >1.vars 关键字 [roo ...

  3. ASP.NET MVC中使用MvcPager异步分页+在分页中复选框下一页上一页也保持选中

    ASP.NET MVC 分页使用的是作者杨涛的MvcPager分页控件  地址:http://www.webdiyer.com/mvcpager/demos/ajaxpaging/ 这个分页控件在里面 ...

  4. Flutter 快速上手定时器/倒计时及实战讲解

    本文微信公众号「AndroidTraveler」首发. 今天给大家讲讲 Flutter 里面定时器/倒计时的实现. 一般有两种场景: 我只需要你在指定时间结束后回调告诉我.回调只需要一次. 我需要你在 ...

  5. SpringBoot项目下的JUnit测试

    在SpringBoot项目里,要编写单元测试用例,需要依赖4个jar.一个是最基本的JUnit,然后是spring-test和spring-boot-test. <!--test--> & ...

  6. 抖音短视频教程VIP培训课程(2019实时更新中)

    抖音联盟,抖友会,抖音联盟会员,抖音联盟学员,抖音批量做号团队,工作室带队,联盟学员统一官网认证可查,统一变现渠道担保,成熟技术技术后盾,实时工作室真机实测规则,抖音情感励志书单模式2.0升级,拒绝落 ...

  7. 请求*.html后缀无法返回json数据的问题

    在springmvc中请求*.html不可以返回json数据. 修改web.xml,添加url拦截格式.

  8. PHP switch的写法

    switch switch (expression) { case label1: expression = label1 时执行的代码 ; break; case label2: expressio ...

  9. rpm包安装java jar开机自启

    1.安装jdk: rpm -ivh jdk-8u201-linux-x64.rpm 2.配置jdk路径 打开/etc/profile增加以下内容: export JAVA_HOME=/usr/java ...

  10. 关于thymeleaf中th:if的使用

    运用于判断表达式中时,关系判断使用 gt / ge / eq / lt / le / ne (即:使用缩写) gt: great than(大于)> ge: great equal(大于等于)& ...