zoukankan      html  css  js  c++  java
  • 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

    题意

    就是经典的数独问题。

    思路:

    搜索。

    可是得借助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 ",path); } return 0; }


    版权声明:本文博主原创文章。博客,未经同意不得转载。

  • 相关阅读:
    angularJS获取json数据(实战)
    HTML中使背景图片自适应浏览器大小
    实现table的单线边框的办法
    [转载]姑娘,你为什么要编程呢?
    可拖拽和带预览图的jQuery文件上传插件ssiuploader
    table布局的简单网页
    3D立体照片墙
    五一假期安排
    有点小迷惘
    一直都不明白,现在还是木有明白,那些人,那些事——残念
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4843723.html
Copyright © 2011-2022 走看看