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 ...
随机推荐
- LinqDB 查询数据库
LinqDB数据库查询数据,还是很方便的. 1. 添加Entity数据实体类 方便之后映射操作 /// <summary> /// 课件 /// </summary> [Dat ...
- Java生鲜电商平台-优惠券功能设计与开发(小程序/APP)
Java生鲜电商平台-优惠券功能设计与开发(小程序/APP) 说明:Java生鲜电商平台-优惠券功能设计与开发(小程序/APP) 目录 1.项目背景与需求分析 2.需求目的与功能点列表 3.业务逻辑 ...
- Server基本语句的用法
1.创建数据库 create database databaseName use databaseName go /* 转到指定数据库 */ 2.创建表 create table tableNa ...
- Angular + Leaflet 实现房源数据可视化(附github源码)
这是什么?租房信息展示平台 宏观的租房数据可视化微观的房源信息展示多条件搜索等等 链接地图搜租房 来龙去脉 受 @李国宝 的地图搜租房启发,利用其提供的开放API,配合自己在前端和地理信息系统方面的 ...
- python快速导出sql语句(mssql)的查询结果到Excel,解决SSMS无法加载大字段的问题
遇到一个尴尬的问题,SSMS的GridView对于大字段的(varchar(max),text之类的),支持不太友好的,超过8000个长度之外的字符,SSMS的表格是显示不出来的(当然也就看不到了), ...
- 计算机网络基础笔记 运输层协议UDP/TCP
目录 UDP 首部结构 主要特点 TCP 首部结构 主要特点 TCP 可靠性实现 停止等待ARQ协议 连续ARQ协议&滑动窗口协议 拥塞控制 TCP 运输连接管理 连接建立:三次握手 连接释放 ...
- dp习题
仅收录有意思的题目 数的划分 导弹拦截 : LIS的两种优化 教主的花园:将不同的情况分类,最后取max 午餐 & 挂饰: 需要排序 挂饰:0-1背包处理负数体积 投资的最大效益 : 完全背包 ...
- 为什么有的插件安装需要用Vue.use()方法
问题 相信很多人在用Vue使用别人的组件时,会用到 Vue.use() .例如:Vue.use(VueRouter).Vue.use(MintUI).但是用 axios时,就不需要用 Vue.use( ...
- koa2跨域模块koa2-cors
之前写了一个api在小程序里调用,但是我不想每次都打开小程序,所以想写一个简单的网页,但是遇到CORB的问题: 经尝试,jsonp等都没起作用,由于我后台是koa写的,发现koa2-cors库可以解决 ...
- Spring 中的观察者模式
一.Spring 中观察者模式的四个角色 1. 事件(ApplicationEvent) ApplicationEvent 是所有事件对象的父类.ApplicationEvent 继承自 jdk 的 ...