poj 3074 Sudoku(Dancing Links)


Sudoku

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

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

Stanford Local 2006

题意:

就是经典的数独问题。

思路:

搜索。但是得借助Dancing Links加速。关键就在于怎样把数独问题抽象成一个精确覆盖问题了。

我们首先考虑数独的游戏规则。

1.每个格子都必须填一个数字。

2.每一行1-9这几个数字都必须出现一次。

3.每一列1-9这几个数字都必须出现一次。

4.每一宫格1-9这几个数字都必须出现一次。

我们知道Dancing Links的精确覆盖智能处理0,1的序列覆盖每一列为一个约束条件。那么我们就必须把上述约束转换成0,1矩阵。

对于1。我们用第(i-1)*9+j列为1表示i行j列的已经填数。一共占用81列。

对于2.我们用81+(i-1)*9+v列表示第i行已经有v这个值。一共占用81列。

对于3.我们用162+(j-1)*9+v列表示第j列已经有v这个值。一共占用81列。

对于3.我们用243+(3*((i-1)/3)+(j+2)/3-1)+v列表示第3*((i-1)/3)+(j+2)/3宫格已经有v这个值。一共占用81列。

ps:i,j都从1开始。3*((i-1)/3)+(j+2)/3为通过i,j确定的宫格数。

这样就会为每个宫格确定一个01序列约束。

然后建好矩阵后。套上精确覆盖模板后就ok了。

详细见代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int INF=0x3f3f3f3f;const int maxn=3645;//每个格子可能有9个取值。所以最多有81*9行。然后243列。
int U[maxn],D[maxn],L[maxn],R[maxn],C[maxn],row[maxn];//上下左右指针。c[i]结点i对应的列。row[i]结点i对应的行号。
int S[350],H[800],ans[100];//S[i]为i列1的个数。H[i]为i行的尾指针。
int n,m,cnt,deep;
struct node
{
    int x,y,v;
} st[maxn];
char maze[150],path[150];
void init()
{
    int i;
    for(i=1;i<=800;i++)
        H[i]=-1;
    for(i=0;i<=324;i++)
    {
         S[i]=0;
         L[i+1]=i;
         R[i]=i+1;
         U[i]=D[i]=i;
    }
    R[324]=deep=0;
    cnt=325;
}
void Insert(int r,int c)
{
                        //头插法建链表
    U[cnt]=c,D[cnt]=D[c];//确定新增结点上下指针信息
    U[D[c]]=cnt,D[c]=cnt;//恢复链表信息
    if(H[r]==-1)         //确定左右指针信息
        H[r]=L[cnt]=R[cnt]=cnt;//加入头
    else
    {
        L[cnt]=H[r],R[cnt]=R[H[r]];//头插法
        L[R[H[r]]]=cnt,R[H[r]]=cnt;
    }
    S[c]++;//更新附加信息
    row[cnt]=r;
    C[cnt++]=c;
}
void Remove(int c)//移除c列。
{
    int i,j;
    R[L[c]]=R[c],L[R[c]]=L[c];
    for(i=D[c];i!=c;i=D[i])
        for(j=R[i];j!=i;j=R[j])
            D[U[j]]=D[j],U[D[j]]=U[j],S[C[j]]--;
}
void Resume(int c)//还原c列。
{
    int i,j;
    R[L[c]]=L[R[c]]=c;
    for(i=D[c];i!=c;i=D[i])
        for(j=R[i];j!=i;j=R[j])
            D[U[j]]=U[D[j]]=j,S[C[j]]++;
}
bool dfs()
{
    if(R[0]==0)
        return true;
    int i,j,c,miv=INF;
    for(i=R[0];i;i=R[i])
        if(S[i]<miv)
            miv=S[i],c=i;
    Remove(c);//处理第c列
    for(i=D[c];i!=c;i=D[i])
    {
        for(j=R[i];j!=i;j=R[j])
            Remove(C[j]);
        ans[deep++]=row[i];
        if(dfs())
            return true;
        for(j=L[i];j!=i;j=L[j])
            Resume(C[j]);
        deep--;
    }
    Resume(c);
    return false;
}
int main()
{
    int i,j,v,r,p;
    while(gets(maze))
    {
        if(maze[0]=='e')
            break;
        init();
        r=1;
        for(i=1;i<=9;i++)//每行为一个格子的一种选择。
        {
            for(j=1;j<=9;j++)
            {
                if(maze[(i-1)*9+j-1]=='.')
                {
                    for(v=1;v<=9;v++)
                    {
                        Insert(r,(i-1)*9+j);
                        Insert(r,81+(i-1)*9+v);
                        Insert(r,162+(j-1)*9+v);
                        Insert(r,243+(((i-1)/3)*3+(j+2)/3-1)*9+v);
                        st[r].x=i,st[r].y=j,st[r].v=v;
                        r++;
                    }
                }
                else
                {
                    v=maze[(i-1)*9+j-1]-'0';
                    Insert(r,(i-1)*9+j);
                    Insert(r,81+(i-1)*9+v);
                    Insert(r,162+(j-1)*9+v);
                    Insert(r,243+(((i-1)/3)*3+(j+2)/3-1)*9+v);
                    st[r].x=i,st[r].y=j,st[r].v=v;
                    r++;
                }
            }
        }
        dfs();
        for(i=0;i<deep;i++)
        {
            p=ans[i];
            path[(st[p].x-1)*9+st[p].y-1]='0'+st[p].v;
        }
        path[deep]=0;
        printf("%s\n",path);
    }
    return 0;
}

poj 3074 Sudoku(Dancing Links),布布扣,bubuko.com

时间: 2024-10-11 17:48:55

poj 3074 Sudoku(Dancing Links)的相关文章

POJ 3076 Sudoku (dancing links)

题目大意: 16*16的数独. 思路分析: 多说无益. 想说的就是dancing links 的行是按照 第一行第一列填 1 第一行第二列填 2 -- 第一行第十五列填15 第一行第二列填 1 -- 第二行.... 列的纺织则是 第一行放1,第一行放2,..第十六行放16...第一列放1..第一列放2...第十六列放16..第一块区域放1 ....然后在最后81位就是放自己的位置,准确的说就是 r*m+c. #include <cstdio> #include <iostream>

POJ 3074 Sudoku (DLX)

Sudoku Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 3074 Appoint description:  System Crawler  (2015-04-18) Description In the game of Sudoku, you are given a large 9 × 9 grid divided into sm

poj 3074 Sudoku dlx解数独

分析: dlx是从数据结构角度优化01矩阵精确覆盖和重复覆盖的数据结构,它用十字链表只存贮矩阵中的非0元,而01矩阵精确覆盖dfs过程中矩阵会越来越稀疏而且每次恢复现场会浪费大量时间,dlx恰好能解决这两个问题.本题关键是将数独问题转化为01矩阵精确覆盖.数独转化为精确覆盖问题的方法还是参照Knuth的论文,如果读取到一个格子是空的,那么加9行,分别表示这个格子填1到9这9个数字,如果读取到的格子是一个数字,那么就加一行就可以了,然后列有9*9*4列,前81列表示这一行表示填的是第i行第j列的格

POJ 3074 Sudoku DLX精确覆盖

DLX精确覆盖.....模版题 Sudoku Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8336   Accepted: 2945 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 . .

(简单) POJ 3074 Sudoku, DLX+精确覆盖。

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

POJ 3074 Sudoku 舞蹈链

#include <cstdio> #include <iostream> #include <algorithm> #include <queue> #include <stack> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <vector> #include <cstri

Dancing Links [Kuangbin带你飞] 模版及题解

学习资料: http://www.cnblogs.com/grenet/p/3145800.html http://blog.csdn.net/mu399/article/details/7627862 2份模版 第一份精确覆盖 from POJ 3074 const int N = 9; const int MAXN = N * N * N + 10; const int MAXM = N * N * 4 + 10; const int MAXNODE = MAXN * 4 + MAXM +

POJ 2676 Sudoku (搜索,Dancing Links)

题目: http://poj.org/problem?id=2676 题意: 数独,每行1-9,每列1-9,每3*3小格1-9,填数,不能重复 方法:Dancing Links(16ms)或者DFS暴搜(400-900ms) Dancing Links(DLX) 是为了解决矩阵精确覆盖问题的算法,算法效率非常高 使用DLX解决的问题必须转化为矩阵精确覆盖问题: 1.DLX详解: http://wenku.baidu.com/view/d8f13dc45fbfc77da269b126.html 2

【POJ 3074】 Sudoku

[题目链接] http://poj.org/problem?id=3074 [算法] 将数独问题转化为精确覆盖问题,用Dancing Links求解 转化方法如下 : 我们知道,在一个数独中 : 1.每个格子填且只填一个数 2.每一行填1-9这九个数 3.每一列填1-9这九个数 4.每个格子填1-9这九个数 对于第一个约束条件,我们用81列,表示是否填入 对于第二个约束条件,我们每一行用9列,表示这一行是否有1-9 第三,四个约束条件的处理方式和第二个类似 [代码] #include <algo