hdu1426Sudoku Killer解題報告---數獨(深搜 & 回溯 & 輸入格式控制)
Sudoku Killer
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 10645 Accepted Submission(s): 3152
Problem Description
自從2006年3月10日至11日的首屆數獨世界錦標賽以後,數獨這項遊戲越來越受到人們的喜愛和重視。
據說,在2008北京奧運會上,會將數獨列為一個單獨的專案進行比賽,冠軍將有可能獲得的一份巨大的獎品———HDU免費七日遊外加lcy親筆簽名以及同hdu acm team合影留念的機會。
所以全球人民前仆後繼,為了獎品日夜訓練茶飯不思。當然也包括初學者linle,不過他太笨了又沒有多少耐性,只能做做最最基本的數獨題,不過他還是想得到那些獎品,你能幫幫他嗎?你只要把答案告訴他就可以,不用教他是怎麼做的。
數獨遊戲的規則是這樣的:在一個9x9的方格中,你需要把數字1-9填寫到空格當中,並且使方格的每一行和每一列中都包含1-9這九個數字。同時還要保證,空格中用粗線劃分成9個3x3的方格也同時包含1-9這九個數字。比如有這樣一個題,大家可以仔細觀察一下,在這裡面每行、每列,以及每個3x3的方格都包含1-9這九個數字。
例題:
答案:
Input
本題包含多組測試,每組之間由一個空行隔開。每組測試會給你一個 9*9 的矩陣,同一行相鄰的兩個元素用一個空格分開。其中1-9代表該位置的已經填好的數,問號(?)表示需要你填的數。
Output
對於每組測試,請輸出它的解,同一行相鄰的兩個數用一個空格分開。兩組解之間要一個空行。
對於每組測試資料保證它有且只有一個解。
這題很考驗編碼能力,兩組資料空行,輸入最好要用字串來處理輸入的空格換行,搜尋時還要注意位置搜尋不到後的回溯,單個點確定的九宮格判斷 & 行列重複判斷,搜尋從0開始到所有的'?'均確定
練習時這個題目標籤是基礎搜尋題...其實還是很有難度的
AC Code:
#include <cstdio>
#include <cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<map>
#include<queue>
#include<climits>
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
using namespace std;
typedef long long ll;
static const int MAX_N = 1e6 + 5;
typedef pair<int, int> P; //記錄座標
P vv[80];
int maps[10][10];
int len;
bool flag;
bool is_rigth(int x, int y, int z) {
for(int i = 0; i < 9; i++){
if(maps[i][y] == z) return false;
if(maps[x][i] == z) return false; //判斷行列
}
int fx = x / 3 * 3, fy = y / 3 * 3; //確定所在九宮格
for(int i = fx; i < fx + 3; i++){
for(int j = fy; j < fy + 3; j++){
if(maps[i][j] == z) return false; //九宮格判斷
}
}
return true;
}
void dfs(int s) {
if(flag) return; //剪枝
if(s == len){
for(int i = 0; i < 9; i++){
for(int j = 0; j < 8; j++){
printf("%d ", maps[i][j]);
}
printf("%d\n", maps[i][8]);
}
flag = true;
return ;
}
for(int i = 1; i <= 9; i++){
if(flag) return ; //剪枝
if(is_rigth(vv[s].first, vv[s].second, i)) {
maps[vv[s].first][vv[s].second] = i;
dfs(s + 1);
if(flag) return; //剪枝
}
}
maps[vv[s].first][vv[s].second] = 0; //回溯(該點選擇不合適,重新置0)
}
int main(){
char s[2];
while(scanf("%s", s) != EOF) {
maps[0][0] = (s[0] == '?' ? 0 : s[0] - '0'); //第1行第1個
for(int j = 1; j < 9; j++){
scanf("%s", s);
maps[0][j] = (s[0] == '?' ? 0 : s[0] - '0'); //第1行後8個
}
for(int i = 1; i < 9; i++){
for(int j = 0; j < 9; j++) {
scanf("%s", s);
maps[i][j] = (s[0] == '?' ? 0 : s[0] - '0'); //2 - 9行
}
}
len = 0;
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
if(maps[i][j] == 0) {
vv[len].first = i, vv[len++].second = j;
}
}
}
if(flag) printf("\n"); //之前有過輸入
flag = false;
dfs(0);
}
return 0;
}