回溯法 --數獨
藍橋杯——數獨JAVA
這幾天開始在準備藍橋杯了,想借此來學習一下演算法,提高自己程式設計的能力,前幾天看的一個數獨題,雖然知道是用深度優先去做,但是在做的時候還是遇到了些問題,但是感覺回溯演算法做題時是有一點套路的,所以決定寫下來。
題目:
你一定聽說過“數獨”遊戲。如【圖1.png】,玩家需要根據9×9盤面上的已知數字,推理出所有剩餘空格的數字,並滿足每一行、每一列、每一個同色九宮內的數字均含1-9,不重複。
數獨的答案都是唯一的,所以,多個解也稱為無解。
本圖的數字據說是芬蘭數學家花了3個月的時間設計出來的較難的題目。但對會使用計算機程式設計的你來說,恐怕易如反掌了。
本題的要求就是輸入數獨題目,程式輸出數獨的唯一解。我們保證所有已知資料的格式都是合法的,並且題目有唯一的解。
格式要求,輸入9行,每行9個字元,0代表未知,其它數字為已知。
輸出9行,每行9個數字表示數獨的解。
例如:
輸入(即圖中題目):
005300000
800000020
070010500
400005300
010070006
003200080
060500009
004000030
000009700
程式應該輸出:
145327698
839654127
672918543
496185372
218473956
753296481
367542819
984761235
521839764
再例如,輸入:
800000000
003600000
070090200
050007000
000045700
000100030
001000068
008500010
090000400
程式應該輸出:
812753649
943682175
675491283
154237896
369845721
287169534
521974368
438526917
796318452
資源約定:
峰值記憶體消耗(含虛擬機器) < 256M
CPU消耗 < 2000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入…” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意:不要使用package語句。不要使用jdk1.7及以上版本的特性。
注意:主類的名字必須是:Main,否則按無效程式碼處理。
思路:
首先這題一看就是回溯法,來分析一下這個演算法的實現,首先定義一個全域性的二維陣列,陣列長度為9即可,然後在主函式中輸入二維陣列資料。然後就開始呼叫這裡面最重要的函式get(int row,int col)row:行下標,col:列下標。
但凡是陣列用到了回溯,基本這個函式裡的引數都是下標(題目做的還不是很多,只能說目前是這樣),然後函式裡當超過陣列下標值立即將陣列輸出或者執行其他操作,然後進行判斷,這題裡當陣列值為0時,說明這個位置沒有數填進去,那麼進行1–10的遍歷,開始放值,放值之前要判斷這個數是否和所在行,列,以及同色九宮內的數重複(這裡用is_row_col(int row,int col,int target)函式和is_nine(int row,int col,int target)函式進行判斷),如果返回值都是true,那麼進行賦值操作,並且向下一個數組元素遞迴,當遇到重複值,將陣列元素值置0,回溯。
程式碼
import java.util.Scanner;
public class Main {
private static int[][] data = new int[9][9];
public static void print() {
int t=0;
for(int i=0;i<9;i++) {
for(int j=0;j<9;j++) {
System.out.print(data[i][j]);
t++;
if(t==9) {
System.out.println();
t=0;
}
}
}
}
public static boolean is_row_col(int row,int col,int target) {
boolean test=true;
for(int i=0;i<9;i++) {
if(data[row][i]==target) {
test=false;
break;
}
if(data[i][col]==target) {
test=false;
break;
}
}
return test;
}
public static boolean is_nine(int row,int col,int target) {
boolean test=true;
int row_min=0;
int row_max=0;
int col_min=0;
int col_max=0;
if(row>=0&&row<=2) {
row_min=0;
row_max=2;
}
if(row>=3&&row<=5) {
row_min=3;
row_max=5;
}
if(row>=6&&row<=8) {
row_min=6;
row_max=8;
}
if(col>=0&&col<=2) {
col_min=0;
col_max=2;
}
if(col>=3&&col<=5) {
col_min=3;
col_max=5;
}
if(col>=6&&col<=8) {
col_min=6;
col_max=8;
}
for(int i=row_min;i<=row_max;i++) {
for(int j=col_min;j<=col_max;j++) {
if(data[i][j]==target) {
test=false;
break;
}
}
}
return test;
}
public static void get(int row,int col) {
if(row>=9) {
print();
System.exit(0);
}
if(data[row][col]==0) {
for(int t=1;t<10;t++) {
if(is_row_col(row,col,t)&&is_nine(row,col,t)){
data[row][col]=t;
get(row+(col+1)/9,(col+1)%9);//繼續向下遞迴
}
data[row][col]=0;//回溯
}
}else {
get(row+(col+1)/9,(col+1)%9);
}
}
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
for(int i=0;i<9;i++) {
String ss = s.nextLine();
for(int j=0;j<9;j++) {
data[i][j]=Integer.parseInt(ss.charAt(j)+"");
}
}
get(0,0);
}
}
歡迎指出問題!