蓝桥杯基础练习:2n皇后问题
问题描述
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入格式
输入的第一行为一个整数n,表示棋盘的大小。
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
输出一个整数,表示总共有多少种放法。
样例输入
4
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
样例输出
2
样例输入
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
0
1 import java.util.Scanner; 2 3 public class Main{ 4 static int n,success; //n表示棋盘的长度,success表示放置成功的次数(即要输出的结果) 5 static int[] Column1; //一维数组C表示皇后在每行放置的位置 6 static int[][] board;//表示棋盘 7 8 static void search(int row){//放置黑皇后 9 if(row==n) { //递归边界,如果row等于n,那么所有皇后必然不会冲突 10 11 int[][] board1 = new int[n][n]; //生成新棋盘 12 for(int i=0;i<n;i++){ 13 for(int j=0;j<n;j++) 14 board1[i][j] = board[i][j]; 15 } 16 for(int i=0;i<n;i++){//将黑皇后所在位置更新为“0” 17 board1[i][Column1[i]]=0; 18 } 19 20 int[] Column2 = new int[n]; 21 search1(0,board1,Column2);//放置白皇后 22 23 }else{ 24 for(int i=0;i<n;i++){ 25 if(board[row][i] == 0) continue;//如果此位置为“0”,则跳过此次循环 26 Column1[row] = i;//将第row行的皇后放在第i列 27 boolean book = true; 28 for(int j=0;j<row;j++){ 29 if(Column1[row] == Column1[j] || row-Column1[row] == j-Column1[j] || row+Column1[row]==j+Column1[j]){//判断皇后是否冲突 30 book = false; 31 break;//冲突则结束此次循环 32 } 33 34 } 35 if(book) search(row+1);//不冲突,则继续进行递归 36 } 37 } 38 } 39 40 static void search1(int row,int[][] board1,int[] Column2){//放置白皇后 41 if(row==n) 42 success++;//黑皇后和白皇后都放置成功,success+1 43 else{ 44 for(int i=0;i<n;i++){ 45 if(board1[row][i] == 0) continue; 46 Column2[row] = i; 47 boolean book = true; 48 for(int j=0;j<row;j++){ 49 if(Column2[row] == Column2[j] ||row-Column2[row] == j-Column2[j] || row+Column2[row]==j+Column2[j]){ 50 book = false; 51 break; 52 } 53 54 } 55 if(book) search1(row+1,board1,Column2); 56 } 57 } 58 } 59 60 public static void main(String[] args){ 61 Scanner sc = new Scanner(System.in); 62 success = 0; 63 64 n = sc.nextInt();//录入棋盘数据 65 Column1 = new int[n]; 66 board = new int[n][n]; 67 for(int i=0;i<n;i++){ 68 for(int j=0;j<n;j++){ 69 board[i][j] = sc.nextInt(); 70 } 71 } 72 73 search(0); 74 System.out.println(success); 75 76 } 77 }
思路:递归;需要添加一个一维数组用来记录棋盘放置的位置,数组下标是原棋盘上的行坐标,数组的值是原棋盘上的纵坐标。
对于“使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上”的解决:
如果将整个的棋盘看成一个坐标系,那么对角线方程就是y = kx+b,k只可能取1或-1,所以只需要判断两个位置的横纵坐标差值相等(均为b,不重要),即可判断两个位置是在同一条对角线,就不满足条件。
求八皇后总共有多少个解法?使用DFS搜索。
1 public class Main { 2 static int ans = 0; 3 static boolean[] col = new boolean[10]; 4 static boolean[] x1 = new boolean[20]; 5 static boolean[] x2 = new boolean[20]; 6 public static void main(String args[]){ 7 dfs(0); 8 System.out.println(ans); 9 } 10 11 private static void dfs(int r){ 12 if(r == 8){ 13 ans++; 14 return; 15 } 16 for(int i=0;i<8;i++){ 17 if(check(r,i)){ 18 col[i] = x1[r+i] = x2[r-i+8] = true; 19 dfs(r+1); 20 col[i] = x1[r+i] = x2[r-i+8] = false; 21 } 22 } 23 } 24 25 private static boolean check(int r,int i){ 26 return !col[i] && !x1[r+i] && !x2[r-i+8]; 27 } 28 29 }
答案是:92