zoukankan      html  css  js  c++  java
  • POJ3074 Sudoku —— Dancing Links 精确覆盖

    题目链接: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)的矩阵,然后直接套模板。



    代码如下:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cmath>
      5 #include <algorithm>
      6 #include <vector>
      7 #include <queue>
      8 #include <stack>
      9 #include <map>
     10 #include <string>
     11 #include <set>
     12 #define ms(a,b) memset((a),(b),sizeof((a)))
     13 using namespace std;
     14 typedef long long LL;
     15 const int N = 9;
     16 const int MaxN = N*N*N+10;
     17 const int MaxM = N*N*4+10;
     18 const int maxnode = MaxN*4 + MaxM + 10;
     19 
     20 char g[MaxN];
     21 struct DLX      //矩阵的行和列是从1开始的
     22 {
     23     int n, m, size; //size为结点数
     24     int U[maxnode], D[maxnode], L[maxnode], R[maxnode], Row[maxnode], Col[maxnode];
     25     int H[MaxN], S[MaxM];   //H为每一行的头结点,但不参与循环。S为每一列的结点个数
     26     int ansd, ans[MaxN];
     27 
     28     void init(int _n, int _m)   //m为列
     29     {
     30         n = _n;
     31         m = _m;
     32         for(int i = 0; i<=m; i++)   //初始化列的头结点
     33         {
     34             S[i] = 0;
     35             U[i] = D[i] = i;
     36             L[i] = i-1;
     37             R[i] = i+1;
     38         }
     39         R[m] = 0; L[0] = m;
     40         size = m;
     41         for(int i = 1; i<=n; i++) H[i] = -1;    //初始化行的头结点
     42     }
     43 
     44     void Link(int r, int c)
     45     {
     46         size++; //类似于前向星
     47         Col[size] = c;
     48         Row[size] = r;
     49         S[Col[size]]++;
     50         D[size] = D[c];
     51         U[D[c]] = size;
     52         U[size] = c;
     53         D[c] = size;
     54         if(H[r]==-1) H[r] = L[size] = R[size] = size; //当前行为空
     55         else        //当前行不为空: 头插法,无所谓顺序,因为Row、Col已经记录了位置
     56         {
     57             R[size] = R[H[r]];
     58             L[R[H[r]]] = size;
     59             L[size] = H[r];
     60             R[H[r]] = size;
     61         }
     62     }
     63 
     64     void remove(int c)  //c是列的编号, 不是结点的编号
     65     {
     66         L[R[c]] = L[c]; R[L[c]] = R[c];     //在列的头结点的循环队列中, 越过列c
     67         for(int i = D[c]; i!=c; i = D[i])
     68         for(int j = R[i]; j!=i; j = R[j])
     69         {
     70             //被删除结点的上下结点仍然有记录
     71             U[D[j]] = U[j];
     72             D[U[j]] = D[j];
     73             S[Col[j]]--;
     74         }
     75     }
     76 
     77     void resume(int c)
     78     {
     79         L[R[c]] = R[L[c]] = c;
     80         for(int i = U[c]; i!=c; i = U[i])
     81         for(int j = L[i]; j!=i; j = L[j])
     82         {
     83             U[D[j]] = D[U[j]] = j;
     84             S[Col[j]]++;
     85         }
     86     }
     87 
     88     bool Dance(int d)
     89     {
     90         if(R[0]==0)
     91         {
     92             for(int i = 0; i<d; i++) g[(ans[i]-1)/9] = (ans[i]-1)%9 + '1';
     93             for(int i = 0; i<N*N; i++) printf("%c", g[i]);
     94             printf("
    ");
     95             return true;
     96         }
     97 
     98         int c = R[0];
     99         for(int i = R[0]; i!=0; i = R[i])   //挑结点数最少的那一列,否则会超时,那为什么呢?
    100             if(S[i]<S[c])
    101                 c = i;
    102 
    103         remove(c);
    104         for(int i = D[c]; i!=c; i = D[i])
    105         {
    106             ans[d] = Row[i];
    107             for(int j = R[i]; j!=i; j = R[j]) remove(Col[j]);
    108             if(Dance(d+1)) return true;
    109             for(int j = L[i]; j!=i; j = L[j]) resume(Col[j]);
    110         }
    111         resume(c);
    112         return false;
    113     }
    114 };
    115 
    116 //i、j从0开始,代表着位置; k从1开始,代表着数字
    117 void place(int &r, int &c1, int &c2,int &c3, int &c4, int i, int j, int k)
    118 {
    119     //c1为每个格子一个数, c2为行, c3为列, c4为九宫格
    120     r = (i*N+j)*N+k; c1 = i*N+j+1; c2 = N*N+i*N+k;
    121     c3 = N*N*2+j*N+k; c4 = N*N*3+((i/3)*3+(j/3))*N+k;
    122 }
    123 
    124 DLX dlx;
    125 int main()
    126 {
    127     while(scanf("%s", g) && strcmp(g,"end") )
    128     {
    129         dlx.init(N*N*N, N*N*4);
    130         int r, c1, c2, c3,c4;
    131         for(int i = 0; i<N; i++)
    132             for(int j = 0; j<N; j++)
    133                 for(int k = 1; k<=N; k++)
    134                 if(g[i*N+j]=='.' || g[i*N+j]=='0'+k)
    135                 {
    136                     place(r,c1,c2,c3,c4,i,j,k); //获取位置
    137                     dlx.Link(r,c1);     //加入到矩阵中, 下同
    138                     dlx.Link(r,c2);
    139                     dlx.Link(r,c3);
    140                     dlx.Link(r,c4);
    141                 }
    142         dlx.Dance(0);      //一起摇摆
    143     }
    144     return 0;
    145 }
    View Code
  • 相关阅读:
    thymeleaf时间戳转换
    alerttemplate 时间戳转换
    jQuery.Deferred exception: a.indexOf is not a function TypeError: a.indexOf is not a function
    区分数据是对象还是字符串
    eclipse中选取一列快捷键
    图片拉伸不变型
    这里ajax需要改成同步
    idea如何整理代码格式
    20170311-起早床
    20190310-解决头屑
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7538574.html
Copyright © 2011-2022 走看看