sicily 1317. Sudoku

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 9 x 9 grid made up of 3 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.

 

\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.


According to wikipedia:

The number of valid Sudoku solution grids for the standard 9 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 * 2$\scriptstyle \wedge$7 * 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 9 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

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


题目分析

与1162不同的是要求找到共有几种解法,所以蛮力深搜10s也会超时
优化内容有
一,开三个标记数组,确定在某行,某列,某小宫格是否已经有了某个数字

int inRow[10][10];
int inCol[10][10];
int inBlock[10][10];

二,标记为零的区域,而不是整个盘扫一遍去判断某个位置是否需要填数

struct Test {
  int row, col, poss;
  bool valid[10];
} nodes[81];
poss记录其可填的数值个数
valid标记那些数字可以填

三,将nodes按照poss值排序在深搜,这样可以减少搜索的分支和回溯的时间


然后格式要求每个样例后面加空行


#include <iostream>
#include <algorithm>
#include <memory.h>

int sudoku[10][10];
int inRow[10][10];
int inCol[10][10];
int inBlock[10][10];
struct Test {
  int row, col, poss;
  bool valid[10];
} nodes[81];
int count;
int ans;
std::string solution;

int getBlockId(int row, int col) {
  return (row-1)/3*3 + (col-1)/3 + 1;
}

void getPoss() {
  for (int i = 0; i < count; ++i) {
    int rr = nodes[i].row;
    int cc = nodes[i].col;
    for (int j = 1; j <= 9; ++j) {
      if (inRow[rr][j] || inCol[cc][j] || inBlock[getBlockId(rr,cc)][j]) {
        nodes[i].valid[j] = false;
      } else {
        nodes[i].valid[j] = true;
        ++nodes[i].poss;
      }
    }
  }
/*
std::cout << count << std::endl;
for (int i = 0; i < count; ++i) {
  std::cout << nodes[i].poss << "===";
  for (int j = 1; j <= 9; ++j)
    if (nodes[i].valid[j])
      std::cout << j << "   ";
  std::cout << std::endl;
}
*/
}

bool com(Test a, Test b) {
  return a.poss < b.poss;
}

void storeSol() {
  for (int i = 1; i <= 9; ++i) {
    for (int j = 1; j <= 9; ++j)
      solution = solution + (char)('0' + sudoku[i][j]);
    solution = solution + '\n';
  }
}

void dfs(int index) {
  if (index == count) {
    if (!ans) storeSol();
    ans++;
    return;
  }
  int rr = nodes[index].row;
  int cc = nodes[index].col;
  for (int i = 1; i <= 9; ++i) {
    if (inRow[rr][i] || inCol[cc][i] || inBlock[getBlockId(rr,cc)][i])
      continue;

    sudoku[rr][cc] = i;
    inRow[rr][i] = inCol[cc][i] = inBlock[getBlockId(rr,cc)][i] = true;
    ++index;
    dfs(index);
    sudoku[rr][cc] = 0;
    inRow[rr][i] = inCol[cc][i] = inBlock[getBlockId(rr,cc)][i] = false;
    --index;
  }
}


int main()
{
  int num;
  std::cin >> num;
  for (int id = 1; id <= num; ++id) {
    if (id != 1)
      std::cout << "\n";
    memset(inRow, 0, sizeof(inRow));
    memset(inCol, 0, sizeof(inCol));
    memset(inBlock, 0, sizeof(inBlock));
    count = 0;
    ans = 0;
    solution = "";

    std::string str;
    for (int i = 1; i <= 9; ++i) {
      std::cin >> str;
      for (int j = 1; j <= 9; ++j) {
        if (str[j-1] == '_')
          sudoku[i][j] = 0;
        else
          sudoku[i][j] = str[j-1] - '0';
        if (sudoku[i][j]) {
          inRow[i][sudoku[i][j]] = true;
          inCol[j][sudoku[i][j]] = true;
          inBlock[getBlockId(i,j)][sudoku[i][j]] = true;
        } else {
          nodes[count].row = i;
          nodes[count].col = j;
          nodes[count].poss = 0;
          count++;
        }
      }
    }

    getPoss();
    std::sort(nodes, nodes+count, com);
    dfs(0);

    if (ans == 0) {
      std::cout << "Puzzle " << id << " has no solution" << std::endl;
    } else if (ans == 1) {
      std::cout << "Puzzle " << id << " solution is" << std::endl;
      std::cout << solution;
    } else {
      std::cout << "Puzzle " << id << " has " << ans << " solutions" << std::endl;
    }
  }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值