蓝桥杯-----BASIC-27 2N皇后问题

本文探讨了一个变种的八皇后问题,即在一个n*n的棋盘上放置n个黑皇后和n个白皇后,避免同色皇后在同一行、列或对角线。通过递归和回溯算法,文章提供了一种解决方案,并详细解释了代码实现。

首先题目如下

问题描述

  给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。

输入格式

  输入的第一行为一个整数n,表示棋盘的大小。
  接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。

输出格式

  输出一个整数,表示总共有多少种放法。

样例输入

4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1

样例输出

2

样例输入

4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1

样例输出

0

这里题目要求放置白皇后黑皇后,我们可以先放置白or黑皇后,然后再放置另一个,思路如下

  1. 首先使用一个二维数组map对输入的进行存放,然后对map的每一行的每一列进行遍历,如果是1,则表示可以放置

  2. 找到可以放置的位置(即是在二维数组map中对应数为1)之后,对是否可以放置进行判断,判断同一行,列,斜线是否有同色的皇后

    private static boolean Judge(int r, int c, int s) {
    		
    		//只对在当前所判断的行之前的行,还没有放置的行就不判断了,反正也还没东西
    		//判断对应列是否有冲突
    		for(int i = 0; i <= r; i++) {
    			if(arr[i][c] == s) return false;
    		}
    		
    		//判断左对角线是否有冲突
    		for(int i = r-1, j = c-1; i>=0 && j >= 0; i--, j--) {
    			if(arr[i][j] == s)return false;
    		}
    		
    		//判断右对角线是否有冲突
    		for(int i = r-1, j = c+1; i >= 0 && j < n; i--, j++) {
    			if(arr[i][j] == s)return false;
    		}	
    		
    		return true;
    	}

     

  3. 全部判断完后则对另外一种颜色的皇后进行放置,我们可以用不同的数字来区分皇后,如在map中2表示白皇后,3表示黑皇后,便于判断

完整代码如下

import java.util.Scanner;

public class BASIC_27_2nQueen {

	//设置全局变量
	static int n, Count = 0;
	static int arr[][];
	
	public static void main(String[] args) {
		
		//获取输入
		Scanner sc=new Scanner(System.in);
		n = sc.nextInt();
		arr = new int[n][n];
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < n;j ++) {
				arr[i][j] = sc.nextInt();
			}
		}
		//从第0行放置白色棋子(2为白色,3为黑色)
		Put(0, 2);
		System.out.println(Count);
	}

	/**
	 * 	放置棋子
	 * 
	 * @param r  行号
	 * @param s  类型
	 */
	private static void Put(int r, int s) {
		//展示当前棋盘
		//Show();
		
		//已经判断完所有结果
		if(r == n) {
			if(s == 2) { Put(0, 3); }
			else Count++;
			return;
		}
		
		//还未判断完所有行,则循环判断该行的每一列
		for(int i = 0; i < n; i++) {
			//该位置不可以放皇后,绕开
			if(arr[r][i] !=  1) continue;
			//进行放置可行性判断
			//可以放置
			if(Judge(r, i, s)) {arr[r][i] = s;}
			//不可以放置
			else continue;
			Put(r+1, s);	 //往下一层递归
			arr[r][i] = 1;   //用于后面回溯,将状态还原
		}
		
		return;				 //循环找不到结果,返回上一层
	}

	private static void Show() {
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < n; j++) {
				System.out.print(arr[i][j] + " ");
			}
			System.out.println();
		}
		System.out.println("---------------------------");
		
	}

	private static boolean Judge(int r, int c, int s) {
		
		//只对在当前所判断的行之前的行,还没有放置的行就不判断了,反正也还没东西
		//判断对应列是否有冲突
		for(int i = 0; i <= r; i++) {
			if(arr[i][c] == s) return false;
		}
		
		//判断左对角线是否有冲突
		for(int i = r-1, j = c-1; i>=0 && j >= 0; i--, j--) {
			if(arr[i][j] == s)return false;
		}
		
		//判断右对角线是否有冲突
		for(int i = r-1, j = c+1; i >= 0 && j < n; i--, j++) {
			if(arr[i][j] == s)return false;
		}	
		
		return true;
	}
}

其中回溯的地方要好好理解

		//还未判断完所有行,则循环判断该行的每一列
		for(int i = 0; i < n; i++) {
			//该位置不可以放皇后,绕开
			if(arr[r][i] !=  1) continue;
			//进行放置可行性判断
			//可以放置
			if(Judge(r, i, s)) {arr[r][i] = s;}
			//不可以放置
			else continue;
			Put(r+1, s);	 //往下一层递归
			arr[r][i] = 1;   //用于后面回溯,将状态还原
		}
		
		return;				 //循环找不到结果,返回上一层

    这里如果循环完该行的每一列还是没有找到可以放的位置,就会跳出循环,然后执行return,返回跳出到上一层的Put函数,如代码中的Put(r+1, s);,此时因为这里放了棋子会导致后面放不了,所以要把状态还原为1,表示此处可以放置

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值