2n皇后
问题描述:
给定一个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
相比于前几道dfs的算法题,这道就是比较难,本身的选择就很难,况且这不是八皇后,只放黑皇后的问题,这是黑白皇后一起放的问题。(这个黑白问题一起放只需该一行代码,很巧妙)
import java.util.Scanner;
/**
* @author sjf
* @date 2020/3/3 11:56
*/
public class dfs_2n_queen {
static int n; //棋盘的大小
static int[][] map = new int[8][8]; //棋盘存储
static int ans;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
//刻画棋盘
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
map[i][j] = sc.nextInt();
}
}
dfs(0,6);
System.out.println(ans);
}
//逐行遍历
public static void dfs(int x,int queen) {
if (x == n) {
if(queen==6)
dfs(0,9);
else {
ans++;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println();
}
}
return;
}
//遍历每列
for (int j = 0; j < n; j++) {
if (map[x][j] == 1 && judge(x, j ,queen)) {
map[x][j] = queen;
dfs(x + 1,queen);
map[x][j] = 1;
}
}
return;
}
public static boolean judge(int t, int i,int queen) //满足题目要求的判断函数
{
//当前位置上方是否进行了相同皇后的放置 这行以下的还没放不检查
for (int q = t - 1; q >= 0; q--)
if (map[q][i] == queen)
return false;
//检查左对角线 这行以下的还没放不检查
for (int q = t - 1, w = i - 1; q >= 0 && w >= 0; q--, w--)
if (map[q][w] == queen)
return false;
//检查右对角线 这行以下的还没放不检查
for (int q = t - 1, w = i + 1; q >= 0 && w <= n - 1; q--, w++)
if (map[q][w] == queen)
return false;
return true;
}
}
巧妙之处在于:
/*
如果在摆放好黑皇后的棋盘基础之上,再开始摆放白皇后
*/
if (x == n) {
if(queen==6)
dfs(0,9);
总结:
(以前的博客有讲到)
一、全排列
相当于往盒子里面放东西,一维的操作,dfs在盒子中来回搜索
需要一个标记数组。
回溯:回退之后立马回溯
出口:没盒子走的时候,输出序列然后返回接着
最终退回:是第一次dfs循环结束时,也就是全排列 (比如是3!)3开头的搜索完之后,dfs终止。
二、走迷宫
走迷宫就开始接触图的遍历了,此问题需要在每个点都进行上下左右四种重复尝试,也需要一个标记数组来标记走过的点。
回溯:回退之后立马回溯
出口:走出迷宫(到达目的点) 点判定
最终退回:搜索所有结果完之后
三、数独
这种问题不是像走迷宫一样 四个方向都需要尝试
只需逐一遍历一遍,每行填的结果都是一定的
回溯:可以让1-9填数循环之后再开始回溯
出口:行数进行完之后
最终退回:一遍遍历之后,直接退出
/*注意 System.exit(0)
是直接退回到调用dfs方法的位置,
也就是main方法*/
if(x==9){ //当x为9时,也就是遍历完整个数独游戏的时候
print();
System.exit(0); //直接返回第一步,这里不回溯
}
四、2n_queen
这类问题 放置问题,和数独一样逐一遍历,
回溯:回退过来立马回溯
出口:行数进行完之后
最终退回:第一次递归的循环结束
由于此问题的特殊性,所以dfs每次直接进入下一行就可以了
黑白皇后问题:
/*如果在摆放好黑皇后的棋盘基础之上,再开始摆放白皇后*/
if (x == n) {
if(queen==6)
dfs(0,9);