2n皇后问题 Java描述

题目描述
给定一个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

思路一:和n皇后问题一样,可以看成全排列生成问题,直观一点的叙述则为采用递归回溯。
首先用vi数组存放棋盘格子

有白黑皇后,先放哪个都一样。
若先放白,只需检查有无行类对角线冲突和vi数组是否为1;

放完白再放黑,需检查有无行列对角线冲突和vi数组是否为1以及该格子有没有放白

import java.util.Scanner;


public class Main {
	static int n;
	static int tot=0;
	static int[] white=new int[8];	//该行白皇后放在哪一列
	static int[] black=new int[8];   //该行黑皇后放在哪一列
	
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		n=sc.nextInt();
		int[][] vi=new int[n][n];
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				vi[i][j]=sc.nextInt();
		
		whiteEen(vi,0);
		System.out.println(tot);
	}
	public static void whiteEen(int[][] vi,int cur){
		if(cur==n) blackEen(vi,0);
		else 
			for(int i=0;i<n;i++){  //枚举列  cur行 i列
				if(vi[cur][i]==0)
					continue;
				else if(check_w(cur,i)){
					white[cur]=i;
					 whiteEen(vi,cur+1);
				}
			}
		
	}
	public static void blackEen(int[][] vi,int cur){
		if(cur==n) tot++;
		else 
			for(int i=0;i<n;i++){
				if(vi[cur][i]==0 || white[cur]==i)
					continue;
				else if(check_b(cur,i)){
					black[cur]=i;
					 blackEen(vi,cur+1);
				}
			}
		
	}
	public static boolean check_w(int x,int y){
		for(int k=0;k<x;k++)
			if( y==white[k] ||Math.abs(x-k)==Math.abs(y-white[k]) ) //white[k]-k==y-x || white[k]+k==y+x 可替换Math.abs(x-k)==Math.abs(y-white[k])
				return false;
		return true;
	}
	public static boolean check_b(int x,int y){
		for(int k=0;k<x;k++)
			if( y==black[k] ||Math.abs(x-k)==Math.abs(y-black[k]) ) //black[k]-k==y-x ||  black[k]+k==y+x  同上
				return false;
		return true;
	}
	
}

思路二:
典型dfs回溯,思路同上,只是用dfs改写


import java.util.Scanner;
public class Main {
	static int cnt = 0;   //计数变量
	static int n =0;
	static int[][] vis= new int[8][8];
	static int[] white=new int[8];	//放在哪一列
	static int[] black=new int[8];   //放在哪一列
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		n= in.nextInt();
		  //0表示不能放皇后,1表示可以放皇后,2表示已经放置了白皇后,3表示已经放置了黑皇后
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				vis[i][j]=in.nextInt();
		
		dfs(0);
		System.out.println(cnt);
	}
	static void dfs(int cur)
	{
		if(cur==n) {
			cnt++;
			return ; //
		}
		else
			for(int i=0;i<n;i++){     //试放白皇后
				if(judge(cur,i,2)){
					vis[cur][i]=2;		//一行一行地放置白皇后
					white[cur]=i;    //cur=x  i=y
					for(int j=0;j<n;j++){    // //试放黑皇后
						if(judge(cur,j,3)){
							vis[cur][j]=3;   //一行一行地放置黑皇后
							black[cur]=j; 
							dfs(cur+1);
							vis[cur][j]=1;  //回溯       
						}	
					}
					vis[cur][i]=1;  //回溯 ;  white & black 数组为何无需回溯,因为遍历从0至cur
				}
			}
	}
	static boolean judge(int x,int y,int state)  //state为2时,函数判定白皇后,否则是黑皇后
	{  
		if(vis[x][y]!=1)	return false;
		if(state==2)
			for(int k=0;k<x;k++){   //检查同列  k x
				if(vis[k][y]==state || white[k]-k==y-x || white[k]+k==y+x)   
					return false; //white[k]-k==y-x  一开始y误写成white[x],其实white[x]还未确定或用的是之前一波的数据
			}	
		if(state==3)
			for(int k=0;k<x;k++){   //检查同列  k x
				if(vis[k][y]==state || black[k]-k==y-x || black[k]+k==y+x) 
					return false;
			}
		return true;
	}
}
	
发布了23 篇原创文章 · 获赞 10 · 访问量 4990

猜你喜欢

转载自blog.csdn.net/Fzidx/article/details/104190341