回溯法—N皇后问题—java实现

问题描述:

    要求在一个n×n的棋盘上放置n个皇后,使得它们彼此不受攻击。

    按照国际象棋的规则,一个皇后可以攻击与之同一行或同一列或同一斜线上的任何棋子。

    因此,n皇后问题等价于:要求在一个n×n的棋盘上放置n个皇后,使得任意两个皇后不在同一行或同一列或同一斜线上。


一个皇后的攻击范围:

                                    


n皇后的解空间—完全n叉树:


                        


    要找出“四皇后”问题的解,最可靠的方法就是把各种情况都分析一遍,将符合条件的解找出来。但这样做十分地费时间。

采用回溯算法进行求解,在搜索的过程中,将不满足条件要求的分支树剪去,可以有效地降低算法的时间复杂度


首先定义一个Location类,用来表示棋盘上(实际上就是一个二维数组)点的位置:

static class Location{
		int x;//对应棋盘的行
		int y;//对应棋盘的列
		
		Location(int x,int y){
			this.x = x;
			this.y = y;
		}
		
                //重写toString函数用来输出点的信息
		public String toString() {
			return "(" + x + "," + y + ")";
		}
	}



然后就是判断两个皇后放置的位置是否冲突,需要判断是否在同一行、同一列和同一斜线上,这里所有的符合要求的皇后都放置在一个Location链表中,如果要新加入一个皇后,就必须要与当前链表中所有的皇后都进行冲突比较,如果冲突就放弃这个方案;如果不冲突,继续下一步,直到N个皇后都存在于链表中,才算得到了一个解:

/**
     * 判断位置为loc的皇后是否合法
     */
    private static boolean isLegalLoc(LinkedList<Location> list, Location loc) {
        for(Location each : list){
            if(loc.x == each.x || loc.y == each.y)  //判断是否在同一行或同一列
                return false;
            else if (Math.abs(loc.x - each.x) == Math.abs(loc.y - each.y))  //判断是否在同斜线上
                return false;
        }
        return true;
    }

核心算法:

	/**
     * 主要函数,用回溯法。
     */
    private static void NQueen(LinkedList<Location> list, int x, int y) {   

        if(list.size() == SIZE){  //当list元素个数为SIZE时,表示SIZE个皇后都摆放完毕,打印后即可退出函数。
            printLocation(list);  //打印皇后摆放方式
            return ;
        }

        for(int i = x ; i < SIZE ; i++){
            Location loc = new Location(i, y);
            if(isLegalLoc(list, loc)){
                list.offer(loc);  //将第y行的皇后摆放好
                NQueen(list, 0, y+1);  //开始摆放y+1行的皇后,同样从第0列开始摆放
                list.pollLast();  //每次摆放完一个皇后后,都要将其撤回,再试探其它的摆法。
            }                   
        }           
    }



由于皇后的攻击范围的特性,在这个算法执行时,只用考虑一行或者一列的情况就行,即要么使x=0固定,让y从0到n-1进行;要么反过来让y=0固定,让x从0到n-1进行。这样可以省去很多不必要的比较。

全部代码(其中还包括将N皇后问题的解显示输出的函数):

package quene;

import java.util.LinkedList;
import java.util.Scanner;

public class Com_quene {

	private static int SIZE = 0;//皇后的个数
	private static int count = 0;//记录摆放的方式数
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner input = new Scanner(System.in);
		System.out.println("请输入你要解决几个皇后的问题");
		SIZE = input.nextInt();
		input.close();
		 LinkedList<Location> list = new LinkedList<Location>();
	     NQueen(list, 0, 0);  //从棋盘的第0行第0列开始
	     System.out.println(SIZE + "皇后共有 " + count + "种摆放方式");

	}
	static class Location{
		int x;//对应棋盘的行
		int y;//对应棋盘的列
		
		Location(int x,int y){
			this.x = x;
			this.y = y;
		}
		
		public String toString() {
			return "(" + x + "," + y + ")";
		}
	}
	
	/**
     * 主要函数,用回溯法。
     */
    private static void NQueen(LinkedList<Location> list, int x, int y) {   

        if(list.size() == SIZE){  //当list元素个数为SIZE时,表示SIZE个皇后都摆放完毕,打印后即可退出函数。
            printLocation(list);  //打印皇后摆放方式
            return ;
        }

        for(int i = x ; i < SIZE ; i++){
            Location loc = new Location(i, y);
            if(isLegalLoc(list, loc)){
                list.offer(loc);  //将第y行的皇后摆放好
                NQueen(list, 0, y+1);  //开始摆放y+1行的皇后,同样从第0列开始摆放
                list.pollLast();  //每次摆放完一个皇后后,都要将其撤回,再试探其它的摆法。
            }                   
        }           
    }

	
	/**
     * 判断位置为loc的皇后是否合法
     */
    private static boolean isLegalLoc(LinkedList<Location> list, Location loc) {
        for(Location each : list){
            if(loc.x == each.x || loc.y == each.y)  //判断是否在同一行或同一列
                return false;
            else if (Math.abs(loc.x - each.x) == Math.abs(loc.y - each.y))  //判断是否在同斜线上
                return false;
        }
        return true;
    }

    /**
     * 打印皇后摆放方式
     * @param list
     */
    private static void printLocation(LinkedList<Location> list) {
    	String[][] show = new String[SIZE][SIZE];
    	for(int i = 0;i<SIZE;i++) {
    		for(int j = 0;j<SIZE;j++) {
    			show[i][j] = "0";
    		}
    	}
    	for(Location each : list){
            System.out.print(each.toString() + "\t");
            show[each.x][each.y] = "1";
        }
        System.out.println();
        
        for(int i =0;i<SIZE;i++) {
        	for(int j=0;j<SIZE;j++) {
        		System.out.print(show[i][j] + " ");
        	}
        	System.out.println();
        }
        System.out.println();

        count ++;
    }


}


四皇后问题解的示例:




  • 28
    点赞
  • 92
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
下面是一个基于回溯法Java 代码实现,用于解决 n 皇后问题: ```java public class NQueens { private int[] queens; // 存放皇后所在列的位置 private int n; // 皇后个 private int count; // 解法 public int solveNQueens(int n) { this.n = n; queens = new int[n]; count = 0; backtrack(0); return count; } private void backtrack(int row) { if (row == n) { // 找到一组解 count++; return; } for (int col = 0; col < n; col++) { if (isValid(row, col)) { // 判断该位置是否可以放置皇后 queens[row] = col; backtrack(row + 1); } } } private boolean isValid(int row, int col) { for (int i = 0; i < row; i++) { if (queens[i] == col || Math.abs(row - i) == Math.abs(col - queens[i])) { return false; // 同一列或同一对角线已有皇后 } } return true; } } ``` 在这个实现中,`queens` 组存放每行皇后所在的列位置,`n` 表示皇后个,`count` 初始为 0,用于统计解法。`solveNQueens` 方法返回解法,内部调用 `backtrack` 方法进行回溯搜索。`isValid` 方法用于判断该位置是否可以放置皇后,即该位置所在列、左上对角线、右上对角线是否已经有皇后。 回溯法是一种常用的解决搜索问题的算法,其思路是通过枚举所有可能的解,找到符合条件的解。在 n 皇后问题中,我们从第一行开始,枚举该行的所有位置,判断该位置是否可行,如果可行则继续递归搜索下一行,如果不可行则回溯到上一行。这样,当找到一组解时,我们就可以记录下来并开始寻找下一组解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值