搜索:DLX算法
精确覆盖问题:在一个0-1矩阵中,选定部分行,使得每一列都有且只有一个1。求解一种选法
舞蹈链(Dance Link),也就是一个循环十字链表,可以快速的删掉和恢复某行某列
结合了舞蹈链的搜索就称作DLX算法
这里贴一个用DLX算法解决16×16数独的代码
9×9的直接暴力会更好
// LA2659 Sudoku
// Rujia Liu
#include<cstdio>
#include<cstring>
#include<vector> using namespace std; const int maxr = ;
const int maxn = ;
const int maxnode = ; // 行编号从1开始,列编号为1~n,结点0是表头结点; 结点1~n是各列顶部的虚拟结点
struct DLX {
int n, sz; // 列数,结点总数
int S[maxn]; // 各列结点数 int row[maxnode], col[maxnode]; // 各结点行列编号
int L[maxnode], R[maxnode], U[maxnode], D[maxnode]; // 十字链表 int ansd, ans[maxr]; // 解 void init(int n) { // n是列数
this->n = n; // 虚拟结点
for(int i = ; i <= n; i++) {
U[i] = i; D[i] = i; L[i] = i-, R[i] = i+;
}
R[n] = ; L[] = n; sz = n + ;
memset(S, , sizeof(S));
} void addRow(int r, vector<int> columns) {
int first = sz;
for(int i = ; i < columns.size(); i++) {
int c = columns[i];
L[sz] = sz - ; R[sz] = sz + ; D[sz] = c; U[sz] = U[c];
D[U[c]] = sz; U[c] = sz;
row[sz] = r; col[sz] = c;
S[c]++; sz++;
}
R[sz - ] = first; L[first] = sz - ;
} // 顺着链表A,遍历除s外的其他元素
#define FOR(i,A,s) for(int i = A[s]; i != s; i = A[i]) void remove(int c) {
L[R[c]] = L[c];
R[L[c]] = R[c];
FOR(i,D,c)
FOR(j,R,i) { U[D[j]] = U[j]; D[U[j]] = D[j]; --S[col[j]]; }
} void restore(int c) {
FOR(i,U,c)
FOR(j,L,i) { ++S[col[j]]; U[D[j]] = j; D[U[j]] = j; }
L[R[c]] = c;
R[L[c]] = c;
} // d为递归深度
bool dfs(int d) {
if (R[] == ) { // 找到解
ansd = d; // 记录解的长度
return true;
} // 找S最小的列c
int c = R[]; // 第一个未删除的列
FOR(i,R,) if(S[i] < S[c]) c = i; remove(c); // 删除第c列
FOR(i,D,c) { // 用结点i所在行覆盖第c列
ans[d] = row[i];
FOR(j,R,i) remove(col[j]); // 删除结点i所在行能覆盖的所有其他列
if(dfs(d+)) return true;
FOR(j,L,i) restore(col[j]); // 恢复结点i所在行能覆盖的所有其他列
}
restore(c); // 恢复第c列 return false;
} bool solve(vector<int>& v) {
v.clear();
if(!dfs()) return false;
for(int i = ; i < ansd; i++) v.push_back(ans[i]);
return true;
} }; ////////////// 题目相关
#include<cassert> DLX solver; const int SLOT = ;
const int ROW = ;
const int COL = ;
const int SUB = ; // 行/列的统一编解码函数。从1开始编号
int encode(int a, int b, int c) {
return a*+b*+c+;
} void decode(int code, int& a, int& b, int& c) {
code--;
c = code%; code /= ;
b = code%; code /= ;
a = code;
} char puzzle[][]; bool read() {
for(int i = ; i < ; i++)
if(scanf("%s", puzzle[i]) != ) return false;
return true;
} int main() {
int kase = ;
while(read()) {
if(++kase != ) printf("\n");
solver.init();
for(int r = ; r < ; r++)
for(int c = ; c < ; c++)
for(int v = ; v < ; v++)
if(puzzle[r][c] == '-' || puzzle[r][c] == 'A'+v) {
vector<int> columns;
columns.push_back(encode(SLOT, r, c));
columns.push_back(encode(ROW, r, v));
columns.push_back(encode(COL, c, v));
columns.push_back(encode(SUB, (r/)*+c/, v));
solver.addRow(encode(r, c, v), columns);
} vector<int> ans;
assert(solver.solve(ans)); for(int i = ; i < ans.size(); i++) {
int r, c, v;
decode(ans[i], r, c, v);
puzzle[r][c] = 'A'+v;
}
for(int i = ; i < ; i++)
printf("%s\n", puzzle[i]);
}
return ;
}
搜索:DLX算法的更多相关文章
- [蘑菇街] 搜索、算法团队招募牛人啦-年底了走过路过不要错过 - V2EX
[蘑菇街] 搜索.算法团队招募牛人啦-年底了走过路过不要错过 - V2EX [蘑菇街] 搜索.算法团队招募牛人啦-年底了走过路过不要错过
- 关于用舞蹈链DLX算法求解数独的解析
欢迎访问——该文出处-博客园-zhouzhendong 去博客园看该文章--传送门 描述 在做DLX算法题中,经常会做到数独类型的题目,那么,如何求解数独类型的题目?其实,学了数独的构建方法,那么DL ...
- 【DLX算法】hdu3498 whosyourdaddy
题意:给你一个01矩阵,让你选择尽可能少的行数,使得这些行的并集能够覆盖到所有列. DLX算法求解重复覆盖问题模板,使用估价函数进行剪枝. #include<cstdio> #includ ...
- 【DLX算法】poj2676 Sudoku
DLX算法求解精确覆盖问题模板.赛场上可以参见白书. #include<cstdio> #include<cstring> #include<vector> usi ...
- Python排序搜索基本算法之归并排序实例分析
Python排序搜索基本算法之归并排序实例分析 本文实例讲述了Python排序搜索基本算法之归并排序.分享给大家供大家参考,具体如下: 归并排序最令人兴奋的特点是:不论输入是什么样的,它对N个元素的序 ...
- 搜索相关性算法在 DiDi Food 中的搜索
导读:今天给大家分享的主题是搜索匹配问题在 DiDi Food 中的一些探索与应用.本文首先介绍了搜索相关性的一些背景,之后介绍了业界常见的三种匹配模型,以及在DiDi Food业务中的模型效果对比. ...
- 图的遍历(搜索)算法(深度优先算法DFS和广度优先算法BFS)
图的遍历的定义: 从图的某个顶点出发访问遍图中所有顶点,且每个顶点仅被访问一次.(连通图与非连通图) 深度优先遍历(DFS): 1.访问指定的起始顶点: 2.若当前访问的顶点的邻接顶点有未被访问的,则 ...
- 广度优先搜索 BFS算法
广度优先搜索算法(Breadth-First-Search,BFS),又称作宽度优先搜索.BFS算法是从根节点开始,沿着树的宽度遍历树的节点.如果所有节点均被访问,则算法中止. 算法思想 1.首先将根 ...
- DLX算法一览
目录: 1 X思想的了解. 链表的递归与回溯. 具体操作. 优化. 一些应用与应用中的再次优化(例题). 练手题 X思想的了解. 首先了解DLX是什么? DLX是一种多元未饱和型指令集结构,DLX 代 ...
随机推荐
- PSP1130
PSP时间图: 类型 任务 开始时间 结束时间 净时间 中断时间 日期 开会 开会 16:17 16:50 33 0 20171027 开会 开会 17:00 17:22 22 0 20171028 ...
- 《JavaScript设计模式与开发实践》——第3章 闭包和高阶函数
闭包 变量的作用域和生存周期密切相关 高阶函数 函数可以作为参数被传递 函数可以作为返回值输出
- 关于在eclipse Oxygen 2017环境下spring3.2 asm的异常
今天在oxygen 2017下构建spring3.2+mybatis项目时,发生异常,大概是说无法解析我mapper.class文件,错误发生在core.asm中<unknow:source&g ...
- Web站点性能-宏观手段
1,增加服务器配置,购买性能更强的服务器,cpu.增加内存.增加硬盘(换更大更好的硬盘): 2,修改优化程序: 1)增加缓存: 2)优化代码,优化sql: 3)分离静态资源和动态页面: 3,对服务承担 ...
- POJ题目分类推荐 (很好很有层次感)
著名题单,最初来源不详.直接来源:http://blog.csdn.net/a1dark/article/details/11714009 OJ上的一些水题(可用来练手和增加自信) (POJ 3299 ...
- lintcode-422-最后一个单词的长度
422-最后一个单词的长度 给定一个字符串, 包含大小写字母.空格' ',请返回其最后一个单词的长度. 如果不存在最后一个单词,请返回 0 . 注意事项 一个单词的界定是,由字母组成,但不包含任何的空 ...
- Nodejs学习笔记(二)--- 操作MongoDB数据库
最近看了一些关于mongodb的文章,然后就想知道nodeJS是怎么连接的所以我就尝试去了解了一波(这个菜鸟驿站这个网站还不错,虽然知识文档不是最新的,但是还是蛮好的: 顺便官网地址是这个哦:http ...
- jQuery之过滤选择器
在原有选择器匹配的元素中进一步进行过滤的选择器 * 基本 * 内容 * 可见性 * 属性 需求 1. 选择第一个div 2. 选择最后一个class为box的元素 3. 选择所有class属性不为bo ...
- 201621123037 《Java程序设计》第1周学习总结
#作业01-Java基本概念 1. 本周学习总结 本周学习内容JDK JVM JRE 跨平台 .java .class 关键概念之间的联系: 总的来讲JDK是给开发人员们提供专门用来开发的环境,并且包 ...
- java——线性表接口实现
线性表是存储顺序牌类的数据时最常用的数据结构. 实现线性表有两种方式.第一种是使用数组存储线性表的元素.数组是动态创建的.超过数组的容量时,创建一个 新的更大的数组,并且将当前数组中的元素复制到新建的 ...