sicily 1317 Sudoku

Description

Sudoku is a placement puzzle. The goal is to enter a symbol in each cell of a grid, most frequently a x 9 grid made up of x 3subgrids. Each row, column and subgrid must contain only one instance of each symbol. Sudoku initially became popular in Japan in 1986 and attained international popularity in 2005. ios

 

\epsfbox{p3477.eps}

The word Sudoku means ``single number" in Japanese. The symbols in Sudoku puzzles are often numerals, but arithmetic relationships between numerals are irrelevant. c++


According to wikipedia: 算法

The number of valid Sudoku solution grids for the standard  x 9 grid was calculated by Bertram Felgenhauer in 2005 to be 6,670,903,752,021,072,936,960, which is roughly the number of micrometers to the nearest star. This number is equal to  9! * 72$\scriptstyle \wedge$* 2$\scriptstyle \wedge$* 27, 704, 267, 971 , the last factor of which is prime. The result was derived through logic and brute force computation. The number of valid Sudoku solution grids for the  16 x 16 derivation is not known.

Write a program to find a solution to a x 9 Sudoku puzzle given a starting configuration. 數組

Input

The first line will contain an integer specifying the number of puzzles to be solved. The remaining lines will specify the starting configuration for each of the puzzles. Each line in a starting configuration will have nine characters selected from the numerals 1-9 and the underscore which indicates an empty cell. less

Output

For each puzzle, the output should specify the puzzle number (starting at one) and describe the solution characteristics. If there is a single solution, it should be printed. Otherwise, a message indicating whether there are no solutions or multiple solutions should be printed. The output should be similar to that shown below. All input cases have less than 10,000 solutions. 優化

Sample Input

3
________4
1____9_7_
__37_28__
____7_26_
4_______8
_91_6____
__42_36__
_3_14___9
9________
7_9__2___
3_____891
___39___4
48__6____
__5___6__
____4__23
2___57___
568_____7
___8__4_2
82_______
___5__2__
__6_4_7__
_5___1_7_
9_2_5_4_1
_3_8_6_9_
__3_6_1__
__5__2___
_______34

Sample Output

Puzzle 1 has 6 solutions

Puzzle 2 solution is
719482365
324675891
856391274
482563719
135729648
697148523
243957186
568214937
971836452

Puzzle 3 has no solution

分析:

本題較爲複雜,雖然可以看出明顯應該用深度搜索方法,可是即便時間限制有10s使用暴力算法仍然會超時,須要必定的優化和剪枝。按照作數獨的通常思路,先對數獨空格進行可能性分析將全部格子的可能答案數作記錄(已有的記爲1),而後每次搜索以前先進行篩選,從前向後找答案數最少的進行深搜,一旦搜完再整理結果。剪枝的方案是,搜索時遇到有格子沒法填入數字(即答案數爲0)就返回0值。同時,注意由於深搜是反覆進行的,輸入數組會被反覆還原,可能的答案要另行保存不能使用原有輸入的數組。本題能很好的考察搜索的特色,值得反覆研究,並且數獨也是頗有趣的數學謎題。 spa

PS:注意輸出數據的格式調整。 rest

代碼:

// Problem#: 1317
// Submission#: 1877449
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;

int sudoku[9][9],recnt,ans[9][9],p[82];
bool isvalid[9][9][10],flag;

int dfs(){
    int n = 81;
    int x,y;
    for( int i=0 ; i<81 ; i++ ){
        x = i/9;
        y = i%9;
        if( sudoku[x][y] ) continue;
        if( !p[i] ) return 0;
        if( p[i]>0 && p[i]<p[n] ) n = i;
    }
    if(n==81){
        if( flag ){
            flag = false;
            memcpy(ans,sudoku,sizeof(ans));
        }
        return 1;
    }
    x = n/9;
    y = n%9;
    int trow[81],tcol[81],c;
    int re = 0;
    for( int t=1 ; t<10 ; t++ ){
        if( isvalid[x][y][t] ){
            int tp[82];
            memcpy(tp,p,sizeof(tp));
            sudoku[x][y] = t;
            c = 0;
            p[n] = 0;
            for( int k=0 ; k<9 ; k++ ){
                if( isvalid[k][y][t] ){
                    isvalid[k][y][t] = false;
                    trow[c] = k;
                    tcol[c++] = y;
                    p[k*9+y]--;
                }
                if( isvalid[x][k][t] ){
                    isvalid[x][k][t] = false;
                    trow[c] = x;
                    tcol[c++] = k;
                    p[x*9+k]--;
                }
            }
            for( int r=x/3*3 ; r < (x/3+1)*3 ; r++ )
                for( int s=y/3*3 ; s < (y/3+1)*3 ; s++ )
                    if( isvalid[r][s][t] ){
                        isvalid[r][s][t] = false;
                        trow[c] = r;
                        tcol[c++] = s;
                        p[r*9+s]--;
                    }
            re += dfs();
            for( int i=0 ; i<c ; i++ )
                isvalid[trow[i]][tcol[i]][t] = true;
            memcpy(p,tp,sizeof(p));
            sudoku[x][y] = 0;
        }
    }
    return re;
}

int main(){
    int n;
    char c;
    cin >> n;
    for(int count=1 ; count <= n ; count++){
        recnt = 0;
        flag = true;
        memset(sudoku,0,sizeof(sudoku));
        memset(isvalid,true,sizeof(isvalid));
        memset(p,0,sizeof(p));
        p[81] = 1000;
        for( int i=0 ; i<9 ; i++ ){
            for( int j=0 ; j<9 ; j++ ){
                cin >> c;
                if( c!='_' ){
                    sudoku[i][j] = c - '0';
                    int t = sudoku[i][j];
                    for( int k=0 ; k<9 ; k++ ){
                        isvalid[k][j][t] = k==i;
                        isvalid[i][k][t] = k==j;
                        isvalid[i][j][k+1] = k+1==t;
                    }
                    for( int r=i/3*3 ; r < (i/3+1)*3 ; r++ )
                        for( int s=j/3*3 ; s < (j/3+1)*3 ; s++ )
                            if( r!=i&&s!=j ) isvalid[r][s][t] = false;
                }
            }
        }
        for( int i=0 ; i<9 ; i++ )
            for( int j=0 ; j<9 ; j++ )
                for( int k=1 ; k<10 ; k++ )
                    if( isvalid[i][j][k] ) p[i*9+j]++;
        recnt += dfs();
        cout << "Puzzle " << count;
        if(recnt){
            if( recnt>1 ) cout << " has " << recnt << " solutions" << endl;
            else{
                cout << " solution is" << endl;
                for( int i=0 ; i<9 ; i++ ){
                    for( int j=0 ; j<9 ; j++ )
                        cout << ans[i][j];
                    cout << endl;
                }
            }
        }else{
            cout << " has no solution" << endl;
        }
        if( count<n ) cout << endl;
    }
    return 0;
}
相關文章
相關標籤/搜索