递归+回溯法解决八皇后问题(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();
    	}
    }
}
结果如下:

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