166. 数独 dancing links 方法
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 方法的更多相关文章
- 算法实践——舞蹈链(Dancing Links)算法求解数独
在“跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题”一文中介绍了舞蹈链(Dancing Links)算法求解精确覆盖问题. 本文介绍该算法的实际运用,利用舞蹈链(Dancin ...
- 转载 - 算法实践——舞蹈链(Dancing Links)算法求解数独
出处:http://www.cnblogs.com/grenet/p/3163550.html 在“跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题”一文中介绍了舞蹈链(Dan ...
- hihoCoder #1321 : 搜索五•数独 (Dancing Links ,精确覆盖)
hiho一下第102周的题目. 原题地址:http://hihocoder.com/problemset/problem/1321 题意:输入一个9*9数独矩阵,0表示没填的空位,输出这个数独的答案. ...
- HDU 1426 dancing links解决数独问题
题目大意: 这是一个最简单的数独填充题目,题目保证只能产生一种数独,所以这里的初始9宫格较为稠密,可以直接dfs也没有问题 但最近练习dancing links,这类数据结构解决数独无疑效率会高很多 ...
- Dancing Links and Exact Cover
1. Exact Cover Problem DLX是用来解决精确覆盖问题行之有效的算法. 在讲解DLX之前,我们先了解一下什么是精确覆盖问题(Exact Cover Problem)? 1.1 Po ...
- 算法帖——用舞蹈链算法(Dancing Links)求解俄罗斯方块覆盖问题
问题的提出:如下图,用13块俄罗斯方块覆盖8*8的正方形.如何用计算机求解? 解决这类问题的方法不一而足,然而核心思想都是穷举法,不同的方法仅仅是对穷举法进行了优化 用13块不同形状的俄罗斯方块(每个 ...
- 浅入 dancing links x(舞蹈链算法)
abastract:利用dancing links 解决精确覆盖问题,例如数独,n皇后问题:以及重复覆盖问题. 要学习dacning links 算法,首先要先了解该算法适用的问题,精确覆盖问题和重复 ...
- Dancing Links X 学习笔记
\(\\\) Definitions 双向链表:记录前后两个指针的链表,每个顺序关系都有双向的指针维护. \(Dancing\ Links\):双向十字循环链表,建立在二维关系上,每个元素记录上下左右 ...
- HUST 1017 - Exact cover (Dancing Links 模板题)
1017 - Exact cover 时间限制:15秒 内存限制:128兆 自定评测 5584 次提交 2975 次通过 题目描述 There is an N*M matrix with only 0 ...
随机推荐
- nltk的安装和简单使用
使用python进行自然语言处理,有一些第三方库供大家使用: ·NLTK(Python自然语言工具包)用于诸如标记化.词形还原.词干化.解析.POS标注等任务.该库具有几乎所有NLP任务的工具. ·S ...
- Auto入门 之 常用概念
1.SEMI (Semiconductor Equipment And Materials International) 国际半导体设备与材料产业协会 2.SECS SECS协议是基于RS-232或 ...
- Linux搭建图片服务器减轻传统服务器的压力(nginx+vsftpd)
传统项目中的图片管理 传统项目中,可以在web项目中添加一个文件夹,来存放上传的图片.例如在工程的根目录WebRoot下创建一个images文件夹.把图片存放在此文件夹中就可以直接使用在工程中引用. ...
- MySQL相关参数总结
保留个原文链接,避免被爬虫爬了过去,以便后续更正补充:https://www.cnblogs.com/wy123/p/11273023.html MySQL参数繁多,是一个需要根据具体业务.软硬件环境 ...
- C#后台架构师成长之路-基础体系篇章大纲
如下基础知识点,如果不熟透,以后容易弄笑话..... 1. 常用数据类型:整型:int .浮点型:double.布尔型:bool.... 2. 变量命名规范.赋值基础语法.数据类型的转换.运算符和选择 ...
- appium---模拟点击事件
在做自动化的过程中都会遇到一些无法定位到的地方,或者通过元素怎么都定位不成功的地方,这个时候我们可以使用必杀技,通过坐标定位.具体的怎么操作呢? swipe点击事件 前面安静写过一篇关于swipe的滑 ...
- csp2019后的感慨
你还记得曾经加入oi的初衷吗? ... 我们都不想输,可谁都没有赢... --前言 没有太大的感想,也不配去写感想...就记录一下初学者失败的原因吧.希望看过的人能引以为戒. 做题的时候,不到万不得已 ...
- java.lang.IllegalStateException: getOutputStream() has already been called 解决办法
因为在使用的时候没有使用@ResponseBody这个注解,所以才会报上面的异常
- Eureka工作原理及它和ZooKeeper的区别
1.Eureka 简介: Eureka 是 Netflix 出品的用于实现服务注册和发现的工具. Spring Cloud 集成了 Eureka,并提供了开箱即用的支持.其中, Eureka 又可细分 ...
- 改变JAVA窗体属性的操作方法
在本篇内容里小编给大家详细分析了关于改变JAVA窗体属性的操作方法和步骤,需要的朋友们学习下. 若将JDK版本升级到最新版本,Java窗体就可以简单实现窗体的透明效果,用户可以通过拉动滑块(Slide ...