數獨(深搜 剪枝)
阿新 • • 發佈:2020-12-21
數獨是一種傳統益智遊戲,你需要把一個9 × 9的數獨補充完整,使得圖中每行、每列、每個3 × 3的九宮格內數字1~9均恰好出現一次。
請編寫一個程式填寫數獨。
輸入格式
輸入包含多組測試用例。
每個測試用例佔一行,包含81個字元,代表數獨的81個格內資料(順序總體由上到下,同行由左到右)。
每個字元都是一個數字(1-9)或一個”.”(表示尚未填充)。
您可以假設輸入中的每個謎題都只有一個解決方案。
檔案結尾處為包含單詞“end”的單行,表示輸入結束。
輸出格式
每個測試用例,輸出一行資料,代表填充完全後的數獨。
輸入樣例:
4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......
......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.
end
輸出樣例:
417369825632158947958724316825437169791586432346912758289643571573291684164875293
416837529982465371735129468571298643293746185864351297647913852359682714128574936
#include <iostream> #include <algorithm> #include <cstring> using namespace std; const int N = 9; char str[100]; int ones[1<<N],map[1<<N]; int col[N],row[N],cell[3][3]; void init() { for(int i = 0; i < N; i++) col[i] = row[i] = (1 << N) -1;//每一行每一列都是1 for(int i = 0; i < 3; i ++) { for(int j =0 ; j< 3; j ++) { cell[i][j] = (1<<N)-1;//初始化 每一個九宮格都是1 } } } void draw(int x ,int y , int t , bool is_set) { if(is_set)str[x*N +y] = t +'1'; else str[x * N + y] = '.'; int v = 1 << t; if(!is_set) v = -v; row[x] -=v; col[y]-=v; cell[x/3][y/3] -= v; } int lowbit(int x) { return x & -x; } int get(int x,int y) { return col[y] & row[x] & cell[x/3][y/3];//& 計算出來能放數的位置 } bool dfs(int cnt) { if(!cnt) return true; int maxv = 10; int x, y; for(int i = 0; i < N ; i ++) { for(int j = 0; j < N ; j ++) { if(str[i * N + j] == '.') { int state = get(i,j); if(ones[state] < maxv) { maxv = ones[state]; x = i , y = j ; } } } } int state =get(x,y); for(int i = state; i ; i -= lowbit(i)) { int t = map[lowbit(i)]; draw(x,y,t,true);//把這個數放進去 if(dfs(cnt - 1))return true;//如果能放進去 draw(x,y,t,false); } return false; } int main() { for(int i = 0; i < 1 <<N ; i ++) { int cnt = 0; for(int j = 0; j < N ;j ++) { if(i>> j & 1)cnt++; } ones[i] = cnt;//紀錄每一個二進位制數裡1的個數 } for(int i = 0; i < N ; i ++) map[1 << i] = i;//log 對應的 數是多少 while(cin >> str, str[0] !='e') { init(); int cnt =0; for(int i =0, k =0 ;i < N; i ++) { for(int j =0 ; j< N; j ++,k++) { if(str[k] =='.')cnt++;//能放數的位置 else { int t = str[k]-'1'; draw(i,j,t,true); } } } dfs(cnt); puts(str); } return 0; }