1、n皇后问题
在 n*n 的棋盘上放置 n 个皇后,使它们不同行、不同列、不同对角线。问有多少种合法的情况。输入
4
输出
2
输入
8
输出
92
- 首先我们把这个问题看成具体的皇后数量去思考,比如简单的4皇后
- 摆放的方式有下面这些情况,因为要求不同行,所以我们可以看到我们每一行一定会放置一个,这样才能放置够n个皇后
a[ ] 是为了放置皇后的位置
dfs() 函数就是去完成放置皇后的过程,我们首先从第一行开始
import java.util.Scanner;
public class Nking {
static int n; //n个皇后
static int sum=0; //多少种方法
static int a[]=new int[100];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
n=sc.nextInt(); //n个皇后
dfs(0);
System.out.print(sum);
}
}
1、dfs(0); 开始是第一行,后面会第二行,第三行,形参是 r 代表行,所以后面就是dfs(r+1);
2、当我们满足(r==n)的时候,我们已经放完最后一行也就是n-1行了,这个时候我们sum++,满足的方式++;
3、for (int c = 0; c < n; c++) 这里的for循环是为了,列出同行不同列的所有情况
4、 a[r]=c; a数组是为了存储放置皇后的位置,r 是代表行,a[r] 代表列
5、check(r,c)是一个函数:r行c列的这个位置是否能够放置皇后,也就是和前面的皇后不冲突,也就是和前面的皇后不同行不同列不同对角线
import java.util.Scanner;
public class Nking {
static int n;
static int sum=0; //多少种方法
static int a[]=new int[100];
static void dfs(int r) { //r行
if(r==n) //结束条件
sum++;
for (int c = 0; c < n; c++) { //枚举r行可以放置的列
if(check(r,c)) { //约束条件:r行c列是否可以放置皇后,r行c列满足不同行同列同对角线
a[r]=c; //放置皇后的位置保存起来
dfs(r+1);
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
n=sc.nextInt(); //n个皇后
dfs(0);
System.out.print(sum);
}
}
check(int r, int c)函数判断是否满足条件,那我 r 行 c 列要和前面的皇后进行比较,因为我是一行一行往下面走的,所以我们肯定不同行,a[i]==c 说明同列,
Math.abs(r-i)==Math.abs(c-a[i]) 说明同对角线
Math.abs()是取绝对值的意思
//完整代码如下
import java.util.Scanner;
public class Nking {
static int n;
static int sum=0; //多少种方法
static int a[]=new int[100];
static boolean check(int r, int c) { //r行c列是否可以放置皇后
for (int i = 0; i < r; i++) {
//和之前的皇后进行比较(也就是r的前面行)判断是否冲突 (不要同列同对角线)
if(a[i]==c || Math.abs(r-i)==Math.abs(c-a[i])) //同一列或者同一个对角线
return false;
}
return true;
}
static void dfs(int r) { //r行
if(r==n) //结束条件
sum++;
for (int c = 0; c < n; c++) { //枚举r行可以放置的列
if(check(r,c)) { //约束条件:r行c列是否可以放置皇后,r行c列满足不同行同列同对角线
a[r]=c; //放置皇后的位置保存起来
dfs(r+1);
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
n=sc.nextInt(); //n个皇后
dfs(0);
System.out.print(sum);
}
}
2、受伤的皇后
题目描述
有一个n×n 的国际象棋棋盘(n 行 n 列的方格图),请在棋盘中摆放 n 个受伤的国际象棋皇后,要求:
任何两个皇后不在同一行。
任何两个皇后不在同一列。
如果两个皇后在同一条 45 度角的斜线上,这两个皇后之间行号的差值至少为 3 。
请问一共有多少种摆放方案。
输入描述
输入的第一行包含一个整数 n。
其中,1≤n≤10。
输出描述
输出一个整数,表示答案。输入
4
输出
2
输入
8
输出
1290
1、题目就是多加了一个如果两个皇后在同一条 45 度角的斜线上,这两个皇后之间行号的差值至少为 3 ,和之前的题目相比就是可以同对角线了,只是之间的行号差值要>=3
2、也就是在check函数进行判断的地方进行修改,多加一个 r - i < 3
import java.util.Scanner;
//放置n皇后
public class DFS2 {
static int a[]=new int[100]; //存储皇后放置的位置
static int sum=0;
static int n;
static boolean check(int r,int c) {
for (int i = 0; i <r ; i++) {
if(a[i]==c)
return false;
if(Math.abs(r-i)==Math.abs(c-a[i]) && r-i<3)
return false;
} //满足条件,不在同行同列同3步对角线内
return true;
}
static void dfs(int r) { //r行
if(r==n) //结束状态
sum++;
for (int c = 0; c < n; c++) { //r行 c列
if(check(r,c)) { //满足条件,不在同行同列同3步对角线内
a[r]=c; //放置皇后
dfs(r+1);
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
n=sc.nextInt(); //n个皇后
dfs(0);
System.out.print(sum);
}
}
3、2n皇后
问题描述:
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入格式
输入的第一行为一个整数n,表示棋盘的大小。
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
输出一个整数,表示总共有多少种放法。
先放一个皇后,之后再放另一个皇后
放之前要多加一个判断,这个位置是否为1
import java.util.Scanner;
/*
输入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
输出
2
输入
8
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
输出
3252
*/
public class NNking {
static int res; //结果
static int n; //皇后个数
static int a[]=new int[10]; //存储白皇后每行所放列位置,下标为行的位置 ,n不定,定义最大值10
static int b[]=new int[10]; //存储黑皇后每行所放列位置
static int map[][] =new int[10][10];// 存储棋盘,当map[i][j]=1,表示当前位置可放
static boolean check_a(int r,int c)
{
for(int i=0;i<r;i++) //和已知的每一行皇后判断是否冲突
if(c==a[i] || Math.abs(r-i)==Math.abs(c-a[i]))
return false;
return true;
}
static boolean check_b(int r,int c)
{
for(int i=0;i<r;i++) //和已知的每一行皇后判断是否冲突
if(c==b[i] || Math.abs(r-i)==Math.abs(c-b[i]))
return false;
return true;
}
static void dfs_b(int r)//黑皇后遍历过程
{
if(r==n){
res++;
}
else{
for(int c = 0; c < n; c++){
if(map[r][c]==1&&check_b(r,c)) { // map[r][c]==1才可放置 非同行同列同对角
map[r][c]=0; //放置后置位0
b[r] = c; //记录当前白皇后放置的位置,即第r行放第c列
dfs_b(r+1);
map[r][c]=1;
}}}}
static void dfs(int r)//先是白皇后遍历过程 第r行
{
if(r==n){
dfs_b(0); //遍历黑皇后
}
else{
for(int c = 0; c < n; c++){
if(map[r][c]==1&&check_a(r,c)) { // map[r][c]==1才可放置 非同行同列同对角
map[r][c]=0; //放置后置位0
a[r] = c; //记录当前白皇后放置的位置,即第r行放第c列
dfs(r+1);
map[r][c]=1; //尝试另外一条路,要把刚刚走过的改回1
}}}}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
n=sc.nextInt(); //n个皇后
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
map[i][j]=sc.nextInt(); //棋盘存储到map数组
}
dfs(0);
System.out.print(res);
}
}