1. 程式人生 > >回溯法 --數獨

回溯法 --數獨

藍橋杯——數獨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);
   	
   	
   }
}

歡迎指出問題!