试题 基础练习 2n皇后问题
资源限制
时间限制:1.0s 内存限制:512.0MB
问题描述
给定一个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
—————————————————————————————————————————————————————————————————————————————————————
思路:要解决n皇后问题,2n皇后相当于在n皇后每一种情况分支上再添一层分支,这层分支的处理方法和n皇后相同,但要考虑到其限制条件——已确定父分支的黑皇后分布,因为虽然黑白皇后不会发生直线冲突,但是也不能放在同一个格子里,因此我们需要两个不同的数组或一个二维数组分别储存黑皇后和白皇后的分布,白皇后的优先级低于黑皇后,每次放置需要先查询黑皇后的位置。
static int[][] queen = new int[2][8];//0/1分别代表黑白皇后坐标集
static int n;//数据规模n
static int count;//情况总数
static int[][] map;//建立棋盘
static int round;//区别黑白判定
————注:用static是为了让各函数共享数据,但会带来一个隐患,待会儿再提。
接着我们在主函数中对基本数据进行初始化,queen数组第二维用8个空间,因为题目的数据规模不超过8。
Scanner in = new Scanner(System.in);
n = Integer.parseInt(in.nextLine());
map = new int[n][n];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
map[i][j] = in.nextInt();
for (int i = 0; i < 2; i++)
for (int j = 0; j < 8; j++)
queen[i][j] = -1;
我们需要解决判定问题,这考虑到黑白皇后的判断方法有所区别,我们用round来选择判定函数的实现。
static boolean isLegal(int currentRow,int currentColumn,int round){
if(map[currentRow][currentColumn] == 0) //首先判定棋盘格子是否有效
return false;
if(round == 1)
if(queen[0][currentColumn] == currentRow) //白皇后需要考虑当前位置是否有黑皇后
return false;
for(int preColumn = 0;preColumn < currentColumn;preColumn++){
int row = queen[round][preColumn];//读取某一列在位皇后的行数
if(currentRow == row)
return false;//检测行冲突 不需要考虑列冲突 因为回溯后可无视已定分支
int rowdiffer = Math.abs(currentRow - row);
int columndiffer = currentColumn - preColumn;
if(rowdiffer == columndiffer) //检测是否存在对角线冲突
return false;
}
return true; //经历了前(currentColumn-1)列的考验,可以放置了
}
然后来解决设计黑白皇后求解问题,之前说过它们是同一个问题,所以算法几乎一致,唯一不同的地方在于:白皇后问题隶属于黑皇后问题,其必须出现在黑皇后问题的最后一步,以增加分支;
//这里算法分两步,每一步都是先列后行的DFS搜索,主要问题在于isLegal方法如何实现,它与该算法密不可分。
static void BlackQueen(int currentColumn){
for(int row = 0;row < n;row++){
round = 0;/* 我们此前提到的隐患是也,在每次从白皇后分支返回后,round仍需初始化为0,这是需要格外注意的 */
if(isLegal(row,currentColumn,round)){
queen[round][currentColumn] = row;
if(currentColumn < n-1)
BlackQueen(currentColumn + 1);
else
WhiteQueen(0); //这里是两步算法建立链接的关键,细枝末节由底层分支实现
}
}
}
//
static void WhiteQueen(int currentColumn){
for(int row = 0;row < n;row++){
round = 1;
if(isLegal(row,currentColumn,round)){
queen[round][currentColumn] = row;
if(currentColumn < n-1)
WhiteQueen(currentColumn+1);
else
count++;//达到分支末端后,更改数据并返回对应栈。
}
}
}
最后我们可以执行主方法的最后部分了,然后输出结果。
BlackQueen(0);//参数表示从某一列进入搜索,选0作为实参
System.out.println(count);
最后上完整代码
import java.util.Scanner;
public class Main {
static int[][] queen = new int[2][8];//0/1分别代表黑白皇后坐标集
static int n;//数据规模n
static int count;//情况总数
static int[][] map;//建立棋盘
static int round;//区别黑白判定
public static void main(String[] args){
Scanner in = new Scanner(System.in);
n = Integer.parseInt(in.nextLine());
map = new int[n][n];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
map[i][j] = in.nextInt();
for (int i = 0; i < 2; i++)
for (int j = 0; j < 8; j++)
queen[i][j] = -1;
BlackQueen(0);
System.out.println(count);
}
static boolean isLegal(int currentRow,int currentColumn,int round){
if(map[currentRow][currentColumn] == 0)
return false;
if(round == 1)
if(queen[0][currentColumn] == currentRow)
return false;
for(int preColumn = 0;preColumn < currentColumn;preColumn++){
int row = queen[round][preColumn];
if(currentRow == row)
return false;
int rowdiffer = Math.abs(currentRow - row);
int columndiffer = currentColumn - preColumn;
if(rowdiffer == columndiffer)
return false;
}
return true;
}
static void BlackQueen(int currentColumn){
for(int row = 0;row < n;row++){
round = 0;
if(isLegal(row,currentColumn,round)){
queen[round][currentColumn] = row;
if(currentColumn < n-1)
BlackQueen(currentColumn + 1);
else
WhiteQueen(0);
}
}
}
static void WhiteQueen(int currentColumn){
for(int row = 0;row < n;row++){
round = 1;
if(isLegal(row,currentColumn,round)){
queen[round][currentColumn] = row;
if(currentColumn < n-1)
WhiteQueen(currentColumn+1);
else
count++;
}
}
}
}
通过测试
萌新第一次发帖,也是第一次独立解决初步复杂的算法,难免存在不足,还望各位大神指正、交流。