codevs 2924 數獨挑戰 x(三種做法+超詳細註釋~)
2924 數獨挑戰
時間限制: 1 s 空間限制: 1000 KB 題目等級 : 鉆石 Diamond
題目描述 Description
“芬蘭數學家因卡拉,花費3個月時間設計出了世界上迄今難度最大的數獨遊戲,而且它只有一個答案。因卡拉說只有思考能力最快、頭腦最聰明的人才能破解這個遊戲。”這是英國《每日郵報》2012年6月30日的一篇報道。這個號稱“世界最難數獨”的“超級遊戲”,卻被揚州一位69歲的農民花三天時間解了出來。
看到這個新聞後,我激動不已,證明我們OI的實力的機會來了,我們雖然不是思考能力最快、頭腦最聰明的人,但是我們可以保證在1s之內解題。
好了廢話不多說了……
數獨是一種填數字遊戲,英文名叫Sudoku,起源於瑞士,上世紀70年代由美國一家數學邏輯遊戲雜誌首先發表,名為Number Place,後在日本流行,1984年將Sudoku命名為數獨,即“獨立的數字”的省略,解釋為每個方格都填上一個個位數。2004年,曾任中國香港高等法院法官的高樂德(Wayne Gould)把這款遊戲帶到英國,成為英國流行的數學智力拼圖遊戲。
玩家需要根據9×9盤面上的已知數字,推理出所有剩余位置(數據表示為數字0)的數字,並滿足每一行、每一列、每一個粗線宮內的數字均含1-9,不重復。
現在給你一個數獨,請你解答出來。每個數獨保證有解且只有一個。
輸入描述 Input Description9行9列。
每個數字用空格隔開。0代表要填的數
行末沒有空格,末尾沒有回車。
輸出描述 Output Description輸出答案。
排成9行9列。
行末沒有空格,結尾可以有回車。
樣例輸入 Sample Input2 0 0 0 1 0 8 9 0
0 0 7 0 0 0 0 0 0
0 0 0 9 0 0 0 0 7
0 6 0 0 0 1 3 0 0
0 9 0 7 3 4 0 8 0
0 0 3 6 0 0 0 5 0
6 0 0 0 0 2 0 0 0
0 0 0 0 0 0 1 0 0
0 5 9 0 8 0 0 0 3
2 4 5 3 1 7 8 9 6
9 1 7 2 6 8 5 3 4
3 8 6 9 4 5 2 1 7
4 6 2 8 5 1 3 7 9
5 9 1 7 3 4 6 8 2
8 7 3 6 2 9 4 5 1
6 3 8 1 7 2 9 4 5
7 2 4 5 9 3 1 6 8
1 5 9 4 8 6 7 2 3
保證有解,每個數獨都由<a href="http://oubk.com/">http://oubk.com</a>數獨網提供。
其中數據hard1.in為芬蘭數學家提供。
分類標簽 Tags 點此展開
三種做法+超詳細註釋~
代碼:
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 const int N = 9; 7 const int Group[9][9] = 8 { 9 //便於找出是否在同一個9*9的裏面出現過 10 0, 0, 0, 1, 1, 1, 2, 2, 2, 11 0, 0, 0, 1, 1, 1, 2, 2, 2, 12 0, 0, 0, 1, 1, 1, 2, 2, 2, 13 3, 3, 3, 4, 4, 4, 5, 5, 5, 14 3, 3, 3, 4, 4, 4, 5, 5, 5, 15 3, 3, 3, 4, 4, 4, 5, 5, 5, 16 6, 6, 6, 7, 7, 7, 8, 8, 8, 17 6, 6, 6, 7, 7, 7, 8, 8, 8, 18 6, 6, 6, 7, 7, 7, 8, 8, 8 19 }; 20 21 int a[N][N]; 22 int row[N][N], col[N][N], gr[N][N];//行 列 3*3矩陣 23 24 int judge() 25 { 26 int vis[N]; 27 28 for(int i=0; i<N; i++)//行 29 { 30 for(int j=0; j<N; j++) vis[j] = 0; 31 for(int j=0; j<N; j++) vis[a[i][j]] = 1; 32 for(int j=0; j<N; j++) if(!vis[j]) return 0; 33 } 34 35 for(int i=0; i<N; i++)//列 36 { 37 for(int j=0; j<N; j++) vis[j] = 0; 38 for(int j=0; j<N; j++) vis[a[j][i]] = 1; 39 for(int j=0; j<N; j++) if(!vis[j]) return 0; 40 } 41 42 for(int i=0; i<N; i++)//3*3矩陣 43 { 44 for(int j=0; j<N; j++) vis[j] = 0; 45 for(int j=0; j<N; j++) 46 for(int k=0; k<N; k++) 47 if(Group[j][k] == i) 48 vis[a[j][k]] = 1; 49 for(int j=0; j<N; j++) 50 if(!vis[j]) 51 return 0; 52 } 53 return 1; 54 } 55 56 void print() 57 { 58 //printf("One Possible Solution:\n"); 59 for(int i=0; i<N; i++) 60 { 61 for(int j=0; j<N; j++) 62 printf("%d ", a[i][j] + 1);//因為輸入時減去了1 63 printf("\n"); 64 } 65 } 66 67 void dfs1(int x, int y) 68 { 69 if(x == N)//勝利條件 70 { 71 if(judge()) print();//進行判斷當前所形成的9*9是否滿足條件 72 return; 73 } 74 75 int next_x = x, next_y = y + 1; 76 if(next_y == N) next_x = x + 1, next_y = 0;//繼續下一行 77 78 if(a[x][y] >= 0) dfs1(next_x, next_y);//如果當前位置搜索過了 79 else 80 { 81 for(int i=0; i<N; i++) 82 { 83 a[x][y] = i;//先賦值 84 dfs1(next_x, next_y);//繼續搜索 85 } 86 } 87 } 88 89 void dfs2(int x, int y) 90 { 91 if(x == N)//勝利條件 92 { 93 print(); 94 return; 95 } 96 97 int next_x = x, next_y = y + 1; 98 if(next_y == N) next_x = x + 1, next_y = 0;//進行下一行的搜索 99 100 if(a[x][y] >= 0) dfs2(next_x, next_y);//如果當前的數字被搜索過了 101 else 102 { 103 for(int i=0; i<N; i++) 104 { 105 a[x][y] = -1;//初始化 106 107 int okay = 1; 108 for(int j=0; j<N && okay; j++) 109 if(a[j][y]==i)//當前一列出現過該數字 110 okay = 0;//不滿足,進行標記 111 for(int j=0; j<N && okay; j++) 112 if(a[x][j]==i)//當前一行出現過該數字 113 okay = 0; 114 for(int j=0; j<N && okay; j++) 115 for(int k=0; k<N && okay; k++)//該3*3矩陣中出現過該數字 116 if(Group[j][k]==Group[x][y] && 117 a[j][k]==i) okay = 0; 118 119 if(okay)//如果搜索過後滿足條件 120 { 121 a[x][y] = i;//記錄下來 122 dfs2(next_x, next_y);//進行下一步的搜索 123 } 124 } 125 126 a[x][y] = -1;//回溯 127 } 128 } 129 130 void dfs3(int x, int y) 131 { 132 if(x == N)//勝利條件 133 { 134 print(); 135 return; 136 } 137 138 int next_x = x, next_y = y + 1;//一行一行進行搜索 139 if(next_y == N) next_x = x + 1, next_y = 0; 140 141 if(a[x][y] >= 0) dfs3(next_x, next_y);//該行搜索完成,進行下一行的搜索 142 else 143 { 144 for(int i=0; i<N; i++) 145 if(!row[x][i] && !col[y][i] && !gr[Group[x][y]][i]) 146 { 147 row[x][i] = col[y][i] = gr[Group[x][y]][i] = 1; 148 a[x][y] = i;//記錄下數字 149 dfs3(next_x, next_y); 150 a[x][y] = -1;//回溯 151 row[x][i] = col[y][i] = gr[Group[x][y]][i] = 0; 152 } 153 } 154 } 155 156 int main() 157 { 158 for(int i=0; i<N; i++) 159 for(int j=0; j<N; j++) 160 scanf("%d", &a[i][j]), a[i][j]--;//因為是從0號開始的 161 162 /* 3種做法 */ 163 164 //printf("Dfs Method1:\n"); 165 //dfs1(0, 0); 166 167 //printf("Dfs Method2:\n"); 168 //dfs2(0, 0); 169 170 //printf("Dfs Method3:\n"); 171 172 for(int i=0; i<N; i++)//(將一開始就有的數字進行標記) 173 for(int j=0; j<N; j++)//雙層循環 174 if(a[i][j] >= 0)//如果他是數字,那麽相應的進行標記 175 row[i][a[i][j]] = 1,//該行該數字已經出現過 176 col[j][a[i][j]] = 1,//該列該數字已經出現過 177 gr[Group[i][j]][a[i][j]] = 1; 178 //3*3矩陣的分類,標記在當前的3*3矩陣中該數字已經出現過了 179 180 dfs3(0, 0);//從頭開始進行搜索 181 182 return 0; 183 }
codevs 2924 數獨挑戰 x(三種做法+超詳細註釋~)