[poj3074]Sudoku(舞蹈链)
题目链接:http://poj.org/problem?id=3074
舞蹈链精确覆盖的经典题目,一个数独每个位置的要求,可以得到以下四个约束
1.每个位置有且只有一个数字
2.每个位置的数字在一行只能出现一次
3.每个位置的数字在一列只能出现一次
4.每个位置的数字在一个宫格内只能出现一次
然后针对每个位置可以建立舞蹈链了
前81列,为1条件的约束
82-162列,为2条件的约束
163-243列,为3条件的约束
244-324列,为4条件的约束
则舞蹈链行数为确定的点数+未确定的点数*9,列数为324。
如果i行j列为数k,对应行则在(i - 1) 9 + j列,(i - 1) 9 + k + 81列, (j - 1) 9 + k + 162列,(((i - 1) / 3) 3 + ((j + 2) / 3) - 1)* 9 + k + 243列建立。
如果i行j列为未知数,则k为1-9,对于每个k都应该建立行列关系。
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<string>
#include<algorithm>
#include<set>
#include<cstdlib>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
typedef long long ll;
const int MN = ;
const int MM = ;
const int MNN = MN * MM + ;
struct DLX { int n, m, size;//一共n行m列,size个节点
int U[MNN], D[MNN], L[MNN], R[MNN], row[MNN], col[MNN];//第i个节点的上U下D左L右R,所在位置row行col列
int H[MNN], S[MM];//H数组记录行选择指针,S数组记录覆盖个数
int ansd, ans[MN];//res记录行个数,ans数组记录可行解
void init(int x, int y) {//初始化空表
n = x, m = y;
for (int i = ; i <= m; ++i) {//其中0节点作为head节点,其他作为列首节点
U[i] = D[i] = i;
L[i] = i - ;
R[i] = i + ;
}
R[m] = ; L[] = m;
size = m;
memset(S, , sizeof(S));
memset(H, -, sizeof(H));
}
void Link(int r, int c) {
size++; row[size] = r; col[size] = c; S[c]++;//节点数加一,设置s节点所处位置,以及S列覆盖个数加一
D[size] = D[c]; U[D[c]] = size;//将s节点插入对应列中
U[size] = c; D[c] = size;
if (H[r] < )//如果该行没有元素,H[r]标记该行起始节点
H[r] = L[size] = R[size] = size;
else {//将该节点插入该行第一个节点后面
R[size] = R[H[r]];
L[R[H[r]]] = size;
L[size] = H[r];
R[H[r]] = size;
}
}
//精确覆盖
void remove(int c) {//删除c列
L[R[c]] = L[c]; R[L[c]] = R[c];
//删除该列上的元素对应的行
for (int i = D[c]; i != c; i = D[i]) {//枚举该列元素
for (int j = R[i]; j != i; j = R[j]) {//枚举列的某个元素所在行遍历
U[D[j]] = U[j];
D[U[j]] = D[j];
//将该列上的S数组减一
--S[col[j]];
}
}
}
void resume(int c) {//恢复c列
for (int i = U[c]; i != c; i = U[i]) {//枚举该列元素
for (int j = L[i]; j != i; j = L[j]) {
U[D[j]] = j; D[U[j]] = j;
++S[col[j]];
}
}
L[R[c]] = c; R[L[c]] = c;
}
bool dancing(int deep) {
if (R[] == ) {//当矩阵为空时,说明找到一个可行解,算法终止
ansd = deep;
return true;
}
int c = R[];//找到节点数最少的列,枚举这列上的所有行
for (int i = R[]; i != ; i = R[i]) {
if (S[i] < S[c]) {
c = i;
}
}
remove(c);//删除节点数最少的列
for (int i = D[c]; i != c; i = D[i]) {
ans[deep] = row[i];//将行r放入当前解
for (int j = R[i]; j != i; j = R[j])//行上节点对应的列上进行删除
remove(col[j]);
//进入下一层
if (dancing(deep + ))return true;
//对行上的节点对应的列进行恢复
for (int j = L[i]; j != i; j = L[j])
resume(col[j]);
}
//恢复节点数最少列
resume(c);
return false;
}
};
DLX dzl;
int mp[][];
int x[];
int y[];
int kk[];
int main() {
char s[];
while (cin >> s) {
if (strcmp(s, "end") == )
break;
for (int i = ; i < ; i++) {
int xx = i / ;
int yy = i % ;
if (s[i] == '.')
mp[xx + ][yy + ] = ;
else
mp[xx + ][yy + ] = s[i] - '';
}
dzl.init(, );
int len = ;
for (int i = ; i <= ; i++) {
for (int j = ; j <= ; j++) {
if (mp[i][j] == ) {
for (int k = ; k <= ; k++) {
dzl.Link(len, (i - ) * + j);
dzl.Link(len, (i - ) * + k + );
dzl.Link(len, (j - ) * + k + );
dzl.Link(len, (((i - ) / ) * + ((j + ) / ) - ) * + k + );
x[len] = i, y[len] = j, kk[len] = k;
len++;
}
}
else {
int k = mp[i][j];
dzl.Link(len, (i - ) * + j);
dzl.Link(len, (i - ) * + k + );
dzl.Link(len, (j - ) * + k + );
dzl.Link(len, (((i - ) / ) * + ((j + ) / ) - ) * + k + );
x[len] = i, y[len] = j, kk[len] = k;
len++;
}
}
}
dzl.dancing();
for (int i = ; i < dzl.ansd; i++) {
int r = dzl.ans[i];
mp[x[r]][y[r]] = kk[r];
}
for (int i = ; i <= ; i++) {
for (int j = ; j <= ; j++) {
printf("%d", mp[i][j]);
}
}
puts("");
}
}
[poj3074]Sudoku(舞蹈链)的更多相关文章
- POJ3074 Sudoku 舞蹈链 DLX
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目(传送门) 题意概括 给出一个残缺的数独,求解. 题解 DLX + 矩阵构建 (两个传送门) 代码 #include & ...
- POJ3076 Sudoku 舞蹈链 DLX
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目(传送门) 题意概括 给出一个残缺的16*16数独,求解. 题解 DLX + 矩阵构建 (两个传送门) 学完这个之后,再 ...
- POJ2676 Sudoku 舞蹈链 DLX
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目(传送门) 题意概括 给出一个残缺的数独,求解.SPJ 题解 DLX + 矩阵构建 (两个传送门) 代码 #includ ...
- 算法实践——舞蹈链(Dancing Links)算法求解数独
在“跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题”一文中介绍了舞蹈链(Dancing Links)算法求解精确覆盖问题. 本文介绍该算法的实际运用,利用舞蹈链(Dancin ...
- 舞蹈链 DLX
欢迎访问——该文出处-博客园-zhouzhendong 去博客园看该文章--传送门 舞蹈链是一个非常玄学的东西…… 问题模型 精确覆盖问题:在一个01矩阵中,是否可以选出一些行的集合,使得在这些行的集 ...
- 转载 - 算法实践——舞蹈链(Dancing Links)算法求解数独
出处:http://www.cnblogs.com/grenet/p/3163550.html 在“跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题”一文中介绍了舞蹈链(Dan ...
- 跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题
精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 例如:如下的矩阵 就包含了这样一个集合(第1.4.5行) 如何利用给定的矩阵求出相应的行的集合 ...
- DLX舞蹈链 hdu5046
题意: 在N个城市选出K个城市,建飞机场(1 ≤ N ≤ 60,1 ≤ K ≤ N),N个城市给出坐标,选择这K个机场,使得从城市到距离自己最近的机场的 最大的距离 最小. 输出这个最小值. 思路: ...
- [转] 舞蹈链(Dancing Links)——求解精确覆盖问题
转载自:http://www.cnblogs.com/grenet/p/3145800.html 精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个 ...
随机推荐
- SDK manager打不开解决办法
在下载管理android SDK过程中,有时会出现SDK manager.exe打不开的情况,网上也罗列了各种解决办法,其中地址为http://blog.csdn.net/pipisorry/arti ...
- Mysql查询结果导出Excel表
Mysql查询结果导出Excel表: 一句转换方式:$ mysql -uops -p'GCNgH000KP' dtbs -e 'select * from t_proxy__record;' --de ...
- 随笔1 interface Map<K,V>
第一次写笔记就从map开始吧,如上图所示,绿色的是interface,黄色的是abstract class,蓝色的是class,可以看出所有和图相关的接口,抽象类和类的起源都是interface ma ...
- Linux telnet、nc、ping监测状态
在工作中会遇到网络出现闪断丢包的情况,最终影响业务工常使用.可以业务服务器上发起监测. 1.通过telnet echo -e "\n" | telnet localhost 2 ...
- 前端面试题(4)JavaScript
前端面试题JavaScript(一) JavaScript的组成 JavaScript 由以下三部分组成: ECMAScript(核心):JavaScript 语言基础 DOM(文档对象模型):规定了 ...
- Windows里服务中没有 MySQL
1.以管理员身份启动命令提示符 2.安装并启动MySQL服务 C:\Windows\system32>mysqld.exe -installService successfully instal ...
- hdu 4845 : 拯救大兵瑞恩 (bfs+状态压缩)
题目链接 #include<bits/stdc++.h> using namespace std; typedef long long LL; int n,m,p,s,k; ,,,-}; ...
- SpringBoot 参数校验
一.添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
- git本地创建一个分支并上传到远程服务器上
git branch 查看分支 新建分支:git checkout -b dev 把新建的本地分支push到远程服务器 git push origin 本地名字:外地名字 删除远程分支 git pus ...
- handy源码阅读(二):EventsImp类
EventsImp用于完成事件的处理. class EventsImp { EventBase* base_; PollerBase* poller_; std::atomic<bool> ...