POJ3074 Sudoku —— Dancing Links 精确覆盖
题目链接:http://poj.org/problem?id=3074
| 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 精确覆盖的更多相关文章
- HDU 3111 Sudoku ( Dancing Links 精确覆盖模型 )
推荐两篇学DLX的博文: http://bbs.9ria.com/thread-130295-1-1.html(这篇对DLX的工作过程演示的很详细) http://yzmduncan.iteye.co ...
- 【转】Dancing Links精确覆盖问题
原文链接:http://sqybi.com/works/dlxcn/ (只转载过来一部分,全文请看原文,感觉讲得很好~)正文 精确覆盖问题 解决精确覆盖问题 舞蹈步骤 效率分析 ...
- hihoCoder #1321 : 搜索五•数独 (Dancing Links ,精确覆盖)
hiho一下第102周的题目. 原题地址:http://hihocoder.com/problemset/problem/1321 题意:输入一个9*9数独矩阵,0表示没填的空位,输出这个数独的答案. ...
- hust 1017 dancing links 精确覆盖模板题
最基础的dancing links的精确覆盖题目 #include <iostream> #include <cstring> #include <cstdio> ...
- ZOJ 3209 Treasure Map (Dancing Links 精确覆盖 )
题意 : 给你一个大小为 n * m 的矩形 , 坐标是( 0 , 0 ) ~ ( n , m ) .然后给你 p 个小矩形 . 坐标是( x1 , y1 ) ~ ( x2 , y2 ) , 你选 ...
- HUST1017 Exact cover —— Dancing Links 精确覆盖 模板题
题目链接:https://vjudge.net/problem/HUST-1017 1017 - Exact cover 时间限制:15秒 内存限制:128兆 自定评测 7673 次提交 3898 次 ...
- HDU5046 Airport dancing links 重复覆盖+二分
这一道题和HDU2295是一样 是一个dancing links重复覆盖解决最小支配集的问题 在给定长度下求一个最小支配集,只要小于k就行 然后就是二分答案,每次求最小支配集 只不过HDU2295是浮 ...
- hdu 1426 Sudoku Killer ( Dancing Link 精确覆盖 )
利用 Dancing Link 来解数独 详细的能够看 lrj 的训练指南 和 < Dancing Links 在搜索中的应用 >这篇论文 Dancing Link 来求解数独 , ...
- poj 3074 Sudoku(Dancing Links)
Sudoku Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8152 Accepted: 2862 Descriptio ...
随机推荐
- ElasticSearch索引自定义类型
ES可以自动检测字段并设置映射类型.如果设置的索引类型不是我们所需要的,我们可以自行定义. Rest API设置自定义索引 首先通过ES自动映射一个IP地址的字段的类型: <pre name=& ...
- 【HDOJ5978】To begin or not to begin(概率)
题意:有k个黑球和1个红球,两个轮流抽,抽到红球算赢,问先手赢的概率大还是后手大还是相等 k<=1e5 思路:手算前几项概率 大胆猜想 #include<cstdio> #inclu ...
- noj 2069 赵信的往事 [yy题 无限gcd]
njczy2010 2069 Accepted 31MS 224K 1351Byte G++ 2014-11-13 13:32:56.0 坑爹的无限gcd,,,尼玛想好久,原来要x对y算一次,y再 ...
- android图片上传
package com.example.center; import java.io.ByteArrayOutputStream;import java.io.InputStream; import ...
- T2639 约会计划 codevs
http://codevs.cn/problem/2639/ 题目描述 Description cc是个超级帅哥,口才又好,rp极高(这句话似乎降rp),又非常的幽默,所以很多mm都跟他关系不错.然而 ...
- 如何查看stm32固件库版本及MDK和keil uvision的关系
一.方法如上图: 本人的keil uvision4.12版本如下,晕倒! * Version : V2.0.1* Date : 06/13/2008 二.keil MDK和keil uvision的关 ...
- Spring注入内部的Beans
以下内容引用自http://wiki.jikexueyuan.com/project/spring/injecting-inner-beans.html: 如你所知,Java内部类在其他类的范围内定义 ...
- 天下文章一大抄 mysql远程连接
使用GRANT命令创建远程连接mysql授权用户特定用户mysql -u root -ppassword 注意:p后面没有空格直接密码.mysql>grant all privileges ...
- JDBC连接MySQL数据库的示例代码
虽然老调,但有时也需要用一下,从网上找的原型修改了下放这. import java.sql.Connection; import java.sql.DriverManager; import java ...
- 函数柯里化 curry
一.函数柯里化的特性: (1)参数复用 $.ajax // 示例一 function ajax(type,url,data) { var xhr = new XMLHttpRequest(); xhr ...