码迷,mamicode.com
首页 > 其他好文 > 详细

Sicily 1317. Sudoku

时间:2015-03-31 09:03:13      阅读:209      评论:0      收藏:0      [点我收藏+]

标签:sicily

1317. Sudoku

Constraints

Time Limit: 10 secs, Memory Limit: 32 MB

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 3 subgrids. 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.

 

技术分享

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


According to wikipedia:

The number of valid Sudoku solution grids for the standard x9 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* 2* 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 the16 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.

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

de style=" font-size: 18.01801872253418px;color: rgb(51, 51, 51); line-height: 27.027027130126953px;" >
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

de>

Sample Output

de>
Puzzle 1 has 6 solutions

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

Puzzle 3 has no solution

不剪枝就超时,用时0.29s:

#include <iostream>
#include <vector>
#include <string.h>
#include <cstring>
#include <stdio.h>
#include <algorithm>
using namespace std;

//数独题,深搜,这是剪枝的

char ans[10][10];//用来储存最终答案
char maybe[10][10];//用来深搜
bool num_in_row[10][10], num_in_col[10][10], num_in_blo[10][10];//这里的数组[i][j]表示在第i行/列/块里面已经有了j这个数字(有的时候为true)
int blank_num;//空白的数目
int ans_num;

struct Blank {
    int pos_row, pos_col, pos_blo, possibility;//其中的possibility就是表示可能的数字的个数
}blank[85];

int find_block(int x, int y) {//返回属于的块编号
    
    int block[10][10] = 
    {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 1, 1, 1, 2, 2, 2, 3, 3, 3,
    0, 1, 1, 1, 2, 2, 2, 3, 3, 3,
    0, 1, 1, 1, 2, 2, 2, 3, 3, 3,
    0, 4, 4, 4, 5, 5, 5, 6, 6, 6,
    0, 4, 4, 4, 5, 5, 5, 6, 6, 6,
    0, 4, 4, 4, 5, 5, 5, 6, 6, 6,
    0, 7, 7, 7, 8, 8, 8, 9, 9, 9,
    0, 7, 7, 7, 8, 8, 8, 9, 9, 9,
    0, 7, 7, 7, 8, 8, 8, 9, 9, 9
    };
    
    return block[x][y];
}

void dfs(int blank_now) {//blank_now指当前要填的空的编号
    
    if (blank_now == blank_num) {//如果blank_now超过了总的空白数,也就是说空白都填完了那就返回
        ans_num++;
        if (ans_num == 1) {//这个时候有了答案可以预备输出了
            memcpy(ans, maybe, sizeof(maybe));
        }
        return;
    }
    
    for (int possible = 1; possible <= 9; possible++) {//在一个空上有9种可能
        
        if (!num_in_row[blank[blank_now].pos_row][possible] && !num_in_col[blank[blank_now].pos_col][possible] && !num_in_blo[blank[blank_now].pos_blo][possible]) {
                
            maybe[blank[blank_now].pos_row][blank[blank_now].pos_col] = possible + '0';//先填入答案中,就算不对,后来填的也可以覆盖
            
            num_in_row[blank[blank_now].pos_row][possible] = true;//并更新这个空白的限制信息
            num_in_col[blank[blank_now].pos_col][possible] = true;
            num_in_blo[blank[blank_now].pos_blo][possible] = true;
                
            dfs(blank_now + 1);//深搜
                
            num_in_row[blank[blank_now].pos_row][possible] = false;//程序运行到这说明前面的假设没找到答案,因此还原这个空白的限制信息
            num_in_col[blank[blank_now].pos_col][possible] = false;
            num_in_blo[blank[blank_now].pos_blo][possible] = false;
        }
    }
}

void set_blank(int k, int i, int j) {
    
    blank[k].possibility = 0;
    blank[k].pos_row = i;
    blank[k].pos_col = j;
    blank[k].pos_blo = find_block(i, j);
}

void calculate(int k) {//这里是计算可能的数的个数
    for (int temp = 1; temp <= 9; temp++) {
        if (!num_in_row[blank[k].pos_row][temp] && !num_in_col[blank[k].pos_col][temp] && !num_in_blo[blank[k].pos_blo][temp]) {
            blank[k].possibility++;
        }
    }
}

bool cmp(const Blank &a, const Blank &b) {//按照从小到大的顺序排序
    return a.possibility < b.possibility;
}

int main() {
    
    int case_num, i, j, k;
    scanf("%d", &case_num);
    
    for (k = 1; k <= case_num; k++) {
        
        ans_num = 0;
        blank_num = 0;
        memset(num_in_row, false, sizeof(num_in_row));
        memset(num_in_col, false, sizeof(num_in_col));
        memset(num_in_blo, false, sizeof(num_in_blo));
        
        for (i = 1; i <= 9; i++) {
            scanf("%s", ans[i] + 1);
        }
        
        memcpy(maybe, ans, sizeof(ans));
        
        for (i = 1; i <= 9; i++) {
            for (j = 1; j <= 9; j++) {
                if (ans[i][j] != '_') {//不是空白就更新限制信息
                    
                    num_in_row[i][ans[i][j] - '0'] = true;//更新限制信息
                    num_in_col[j][ans[i][j] - '0'] = true;
                    num_in_blo[find_block(i, j)][ans[i][j] - '0'] = true;
                    
                } else {
                    
                    set_blank(blank_num, i, j);
                    blank_num++;
                
                }
            }
        }
        
        for (i = 0; i < blank_num; i++) {//计算possibility
            calculate(i);
        }
        
        sort(blank, blank + blank_num, cmp);//排序,也就是剪枝
        
        dfs(0);
        
        if (ans_num == 0) {
            printf("Puzzle %d has no solution\n", k);
        } else if (ans_num == 1) {
            printf("Puzzle %d solution is\n", k);
            for (i = 1; i <= 9; i++) {
                printf("%s\n", ans[i] + 1);
            }
        } else {
            printf("Puzzle %d has %d solutions\n", k, ans_num);
        }
        if (k != case_num)
            printf("\n");
        
    }
        
    return 0;
}


Sicily 1317. Sudoku

标签:sicily

原文地址:http://blog.csdn.net/u012925008/article/details/44763065

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!