1. 程式人生 > >codevs 2924 數獨挑戰 x(三種做法+超詳細註釋~)

codevs 2924 數獨挑戰 x(三種做法+超詳細註釋~)

是否 初始化 cst next using 最大 pos 描述 name

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 Description

9行9列。

每個數字用空格隔開。0代表要填的數

行末沒有空格,末尾沒有回車。

輸出描述 Output Description

輸出答案。

排成9行9列。

行末沒有空格,結尾可以有回車。

樣例輸入 Sample Input

2 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

樣例輸出 Sample Output

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

數據範圍及提示 Data Size & Hint

保證有解,每個數獨都由<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(三種做法+超詳細註釋~)