题目链接:http://poj.org/problem?id=3074

Sudoku
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 10451   Accepted: 3776

Description

In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For example,

. 2 7 3 8 . . 1 .
. 1 . . . 6 7 3 5
. . . . . . . 2 9
3 . 5 6 9 2 . 8 .
. . . . . . . . .
. 6 . 1 7 4 5 . 3
6 4 . . . . . . .
9 5 1 8 . . . 7 .
. 8 . . 6 5 3 4 .

Given some of the numbers in the grid, your goal is to determine the remaining numbers such that the numbers 1 through 9 appear exactly once in (1) each of nine 3 × 3 subgrids, (2) each of the nine rows, and (3) each of the nine columns.

Input

The input test file will contain multiple cases. Each test case consists of a single line containing 81 characters, which represent the 81 squares of the Sudoku grid, given one row at a time. Each character is either a digit (from 1 to 9) or a period (used
to indicate an unfilled square). You may assume that each puzzle in the input will have exactly one solution. The end-of-file is denoted by a single line containing the word “end”.

Output

For each test case, print a line representing the completed Sudoku puzzle.

Sample Input

.2738..1..1...6735.......293.5692.8...........6.1745.364.......9518...7..8..6534.
......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.
end

Sample Output

527389416819426735436751829375692184194538267268174593643217958951843672782965341
416837529982465371735129468571298643293746185864351297647913852359682714128574936

Source

题解:

Dancing Links博客(来自万仓一黍 )

Dancing Links的一些特点:

1.矩阵中每个元素的值只能是0或1(在实际操作中只记录1)。

2.行代表着放置情况, 列代表着约束条件。其中矩阵中的行和列的编号从1开始。

3.选择若干行,使得其满足所有约束条件。

对于此题:

1.行:9*9*9,表明有9*9个格子,每个格子有9中情况。

2.列:9*9*4,首先每个格子能且仅能放1个数字,其次每一行的九个数字能且仅能被放一次, 再者列如行者,最后每个九宫格的九个数字能且仅能被放一次。

3.所以构成了(9*9*9) * (9*9*4)的矩阵,然后直接套模板。

代码如下:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
#define ms(a,b) memset((a),(b),sizeof((a)))
using namespace std;
typedef long long LL;
const int N = ;
const int MaxN = N*N*N+;
const int MaxM = N*N*+;
const int maxnode = MaxN* + MaxM + ; char g[MaxN];
struct DLX //矩阵的行和列是从1开始的
{
int n, m, size; //size为结点数
int U[maxnode], D[maxnode], L[maxnode], R[maxnode], Row[maxnode], Col[maxnode];
int H[MaxN], S[MaxM]; //H为每一行的头结点,但不参与循环。S为每一列的结点个数
int ansd, ans[MaxN]; void init(int _n, int _m) //m为列
{
n = _n;
m = _m;
for(int i = ; i<=m; i++) //初始化列的头结点
{
S[i] = ;
U[i] = D[i] = i;
L[i] = i-;
R[i] = i+;
}
R[m] = ; L[] = m;
size = m;
for(int i = ; i<=n; i++) H[i] = -; //初始化行的头结点
} void Link(int r, int c)
{
size++; //类似于前向星
Col[size] = c;
Row[size] = r;
S[Col[size]]++;
D[size] = D[c];
U[D[c]] = size;
U[size] = c;
D[c] = size;
if(H[r]==-) H[r] = L[size] = R[size] = size; //当前行为空
else //当前行不为空: 头插法,无所谓顺序,因为Row、Col已经记录了位置
{
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]; //在列的头结点的循环队列中, 越过列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[Col[j]]--;
}
} void resume(int c)
{
L[R[c]] = R[L[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]] = D[U[j]] = j;
S[Col[j]]++;
}
} bool Dance(int d)
{
if(R[]==)
{
for(int i = ; i<d; i++) g[(ans[i]-)/] = (ans[i]-)% + '';
for(int i = ; i<N*N; i++) printf("%c", g[i]);
printf("\n");
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[d] = Row[i];
for(int j = R[i]; j!=i; j = R[j]) remove(Col[j]);
if(Dance(d+)) return true;
for(int j = L[i]; j!=i; j = L[j]) resume(Col[j]);
}
resume(c);
return false;
}
}; //i、j从0开始,代表着位置; k从1开始,代表着数字
void place(int &r, int &c1, int &c2,int &c3, int &c4, int i, int j, int k)
{
//c1为每个格子一个数, c2为行, c3为列, c4为九宫格
r = (i*N+j)*N+k; c1 = i*N+j+; c2 = N*N+i*N+k;
c3 = N*N*+j*N+k; c4 = N*N*+((i/)*+(j/))*N+k;
} DLX dlx;
int main()
{
while(scanf("%s", g) && strcmp(g,"end") )
{
dlx.init(N*N*N, N*N*);
int r, c1, c2, c3,c4;
for(int i = ; i<N; i++)
for(int j = ; j<N; j++)
for(int k = ; k<=N; k++)
if(g[i*N+j]=='.' || g[i*N+j]==''+k)
{
place(r,c1,c2,c3,c4,i,j,k); //获取位置
dlx.Link(r,c1); //加入到矩阵中, 下同
dlx.Link(r,c2);
dlx.Link(r,c3);
dlx.Link(r,c4);
}
dlx.Dance(); //一起摇摆
}
return ;
}

POJ3074 Sudoku —— Dancing Links 精确覆盖的更多相关文章

  1. HDU 3111 Sudoku ( Dancing Links 精确覆盖模型 )

    推荐两篇学DLX的博文: http://bbs.9ria.com/thread-130295-1-1.html(这篇对DLX的工作过程演示的很详细) http://yzmduncan.iteye.co ...

  2. 【转】Dancing Links精确覆盖问题

    原文链接:http://sqybi.com/works/dlxcn/ (只转载过来一部分,全文请看原文,感觉讲得很好~)正文    精确覆盖问题    解决精确覆盖问题    舞蹈步骤    效率分析 ...

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

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

  4. hust 1017 dancing links 精确覆盖模板题

    最基础的dancing links的精确覆盖题目 #include <iostream> #include <cstring> #include <cstdio> ...

  5. ZOJ 3209 Treasure Map (Dancing Links 精确覆盖 )

    题意 :  给你一个大小为 n * m 的矩形 , 坐标是( 0 , 0 ) ~ ( n , m )  .然后给你 p 个小矩形 . 坐标是( x1 , y1 ) ~ ( x2 , y2 ) , 你选 ...

  6. HUST1017 Exact cover —— Dancing Links 精确覆盖 模板题

    题目链接:https://vjudge.net/problem/HUST-1017 1017 - Exact cover 时间限制:15秒 内存限制:128兆 自定评测 7673 次提交 3898 次 ...

  7. HDU5046 Airport dancing links 重复覆盖+二分

    这一道题和HDU2295是一样 是一个dancing links重复覆盖解决最小支配集的问题 在给定长度下求一个最小支配集,只要小于k就行 然后就是二分答案,每次求最小支配集 只不过HDU2295是浮 ...

  8. hdu 1426 Sudoku Killer ( Dancing Link 精确覆盖 )

    利用 Dancing Link 来解数独 详细的能够看    lrj 的训练指南 和 < Dancing Links 在搜索中的应用 >这篇论文 Dancing Link 来求解数独 , ...

  9. poj 3074 Sudoku(Dancing Links)

    Sudoku Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8152   Accepted: 2862 Descriptio ...

随机推荐

  1. 【CF659F】Polycarp and Hay(并查集,bfs)

    题意: 构造一个矩阵,使得: 矩阵所有格子中数字都小于等于原矩阵,并且至少有一个元素和原矩阵相等, 构造的矩阵除了0以外的数字必须联通并且相等,矩阵中元素之和为K. n,m<=1e3,1< ...

  2. 在GridView中的每一页末尾添加空行

    原文发布时间为:2008-08-03 -- 来源于本人的百度文章 [由搬家工具导入] protected void GridView1_RowCreated(object sender, GridVi ...

  3. C++ 中new

    operator new在C++中的各种写法 (2011-09-21 14:59:33) 标签: 杂谈   乍一看,在C++中动态分配内存很简单:new是分配,delete是释放,就这么简单.然而,这 ...

  4. Linux编译安装Apache+PHP

    Linux编译安装Apache+PHP 来自:自学it网,http://www.zixue.it/. 1]编译安装Apache+PHP 1.安装程序依赖库和开发环境   为了省事把所需要的库文件全都安 ...

  5. MySQL的LOOP, LEAVE 和ITERATE语句(类似Continue、Break的写法)

    和REPEAT和while语句不同,LOOP.LEAVE.ITERATE更像其他编程语言中的goto语句. LOOP要设定一个label指定循环的开始位置,而LEAVE则像其他语言中的Break会离开 ...

  6. Oracle 实现 一个关键字 匹配多个 字段

    有这么一个需求,满足只有一个输入框的条件下,支持不同数据列的搜索结果. 说白了,就是这个 输入框  既可以用来 搜索姓名,也可以搜索 年龄,地址等. 分析: 一般情况下,我们的一个输入框对应 数据库 ...

  7. ROS节点分布式运行方法

    一. 主机Master设置 1.安装ssh客服端和服务器(ubuntu已默认安装了) 2.机器名与ip绑定 由于/etc/hosts中需要将计算机名和IP绑定,所有最好设置IP地址为静态地址 sudo ...

  8. centos下开启htaccess

    不知道原本 centOS是否默认支持 .htaccess 可能是因为我总弄配置文件无意中给搞坏了 今天要用到就查了下怎么开启 想要顺利开启需注意以下几点, 这几点都是在httpd.conf 这个配置文 ...

  9. PPT中的图像失真

    现象:Office PowerPoint 保存出来的PPT文件在WPS下播放的时候会出现图像失真的显现. 解决方法:Office PowerPoint打开PPT将里面的图像另存为BMP格式的图像文件, ...

  10. BUPT复试专题—哈夫曼编码(2009)

    题目描述 哈夫曼编码中  平均码长=码长×码字出现的概率 如:ABCDE 五个字符的出现次数分别为50 20 5 10 15 那么,其哈夫曼编码为A:0   B:10   C:1110   D:111 ...