遞歸+回溯法解決八皇后問題(java實現)

八皇后問題:在一個8*8的棋盤上,放置八個皇后,使得八個皇后之間不能互相攻擊,(皇后不能互相攻擊的條件是兩個皇后之間寂不在同一列或者同一行也不在同一條正斜線或者反斜線上)

算法:我用了回溯+遞歸解決了這題,首先定義一個二維數組保存棋盤,都初始化爲0,定義0表示可以放置皇后,然後寫一個遞歸函數,函數的功能是不停的嘗試下一行,嘗試某一行的時候,假如這一行有位置可以放置的話,就吧這個位置的值設置爲9,因爲1到8要用來標記這個放置的位置在整個棋盤上可以攻擊到的位置,把哪些位置的值設置爲這一行的序數,但是由於我在標記的時候有的位置已經被標記過了,那麼那個位置就不用標記了,用行數來作爲標記的好處是,我在回溯的時候方便知道我上一行做的更改,就這樣一直枚舉到最後第8行,如果第八行有可行解就輸出一個方案,同時result+1,回溯到第一行,第一行枚舉完成之後程序結束,那麼問題來了,怎麼定義這個函數呢?函數如下:

 public static void tryNext(int n){
    	for(int i=0;i<8;i++){
			if(datas[n][i] == 0){
				sign(n,i);
				if(n==7){
					System.out.println("找到了一種方案");
					result +=1;
					printItem();
				}else{
					tryNext(n+1);
				}
				huiSu(n,i);
			}
		}
    }

實際上這是一個類似於模板的函數,對於大部分回溯都可以嘗試用這個模板來解決,全部代碼如下:

public class EightQueen {
   
    static int[][] datas = new int[8][8];
    static int result = 0;
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		for(int i=0;i<8;i++){
			for(int j=0;j<8;j++){
				datas[i][j] = 0;//初始化二維數組,二維數組上的0代表可以放置皇后,1到8代表不可以放置,9代表放置了一個皇后
			}
		}
		
		tryNext(0);
        System.out.println("總共的方案數目是"+result);
	}
	
    public static void tryNext(int n){
    	for(int i=0;i<8;i++){
			if(datas[n][i] == 0){
				sign(n,i);
				if(n==7){
					System.out.println("找到了一種方案");
					result +=1;
					printItem();
				}else{
					tryNext(n+1);
				}
				huiSu(n,i);
			}
		}
    }
    
    public static void sign(int x,int y){
    	int tempx = x;
    	int tempy = y;
		for(int i=0;i<8;i++){
			if(datas[x][i]==0){
				datas[x][i]=tempx+1;//同行的不可以放置
			}
		}
		for(int i=0;i<8;i++){
			if(datas[i][y]==0){
				datas[i][y]=tempx+1;//同列的不可以放置
			}
			
		}
		while(x>0&&y>0){//正斜線上半部分不可以放置
			x--;
			y--;
			if(datas[x][y]==0){
				datas[x][y]=tempx+1;
			}
		}
		x=tempx;
		y=tempy;
		while(x<7&&y<7){//正斜線下半部分不可以放置
			x++;
			y++;
			if(datas[x][y]==0){
				datas[x][y]=tempx+1;
			}
		}
		x=tempx;
		y=tempy;
		while(x>0&&y<7){//反斜線上半部分不可以放置
			x--;
			y++;
			if(datas[x][y]==0){
				datas[x][y]=tempx+1;
			}
		}
		x=tempx;
		y=tempy;
		while(x<7&&y>0){//反斜線下半部分不可以放置
			x++;
			y--;
			if(datas[x][y]==0){
				datas[x][y]=tempx+1;
			}
		}
		
		datas[tempx][tempy]=9;
	}
    public static void huiSu(int x,int y){//回溯,把本行上一次的操作回退
    	datas[x][y]=0;
    	for(int i=0;i<8;i++){
    		for(int j=0;j<8;j++){
    			if(datas[i][j] == x+1){
    				datas[i][j]=0;
    			}
    		}
    	}
    }
    public static void printItem(){
    	for(int i=0;i<8;i++){
    		for(int j=0;j<8;j++){
    			System.out.print(datas[i][j] + " ");
    		}
    		System.out.println();
    	}
    }
}
結果如下:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章