蓝桥杯VIP试题 基础练习 2n皇后问题(python解法+java解法)
资源限制
时间限制: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
python解法:
```python
#(法一):
# 100分
# 先找白皇后再找黑皇后
def chick_W(nums_W, row): #白皇后 #判断当前的位置上放白皇后是否合法
if list1[row][nums_W[row]]==1:
for i in range(row):
#在对角线相当于 x与 y函数运算:y1-y2==x1-x2,即相减的区域形成一个正方形
if abs(nums_W[i] - nums_W[row])==abs(i - row) or nums_W[i]==nums_W[row]:
return False
return True
return False
def chick_B(nums_B, row): #黑皇后 #判断当前的位置上放黑皇后是否合法
if list1[row][nums_B[row]]==1 and nums_W[row]!=nums_B[row]:
for i in range(row):
#在对角线相当于 x与 y函数运算:y1-y2==x1-x2,即相减的区域形成一个正方形
if abs(nums_B[i] - nums_B[row])==abs(i - row) or nums_B[i]==nums_B[row]:
return False
return True
return False
def dfs_W(nums_W, row): #白皇后
if row==n:
dfs_B(nums_B,0) #白皇后排好之后跳到排列黑皇后
return
for i in range(n): #就是要遍历这一行的所有列,看在某个位置上是否合法
nums_W[row]=i
if chick_W(nums_W, row):
dfs_W(nums_W, row + 1)
def dfs_B(nums_B, row): #黑皇后
global count
if row==n:
count+=1
return
for i in range(n): #就是要遍历这一行的所有列,看在某个位置上是否合法
nums_B[row]=i
if chick_B(nums_B, row):
dfs_B(nums_B, row + 1)
n=int(input())
list1=[] #存放原始的0,1位置
for i in range(n):
list1.append(list(map(eval,input().split())))
list2=[]
nums_W=[0 for i in range(n)] #临时放一下白皇后
nums_B=[0 for i in range(n)] #临时放一下黑皇后
count=0
dfs_W(nums_W, 0)
print(count)
#(法二):
# 100分
def chick(nums,row):
for i in range(row):
if abs(nums[i]-nums[row])==abs(i-row) or nums[i]==nums[row]:
return False
return True
def dfs(nums,row):
if row==n:
# for i in range(n):
# list1[i][nums[i]]=0
# print(list1)
list2.append(nums[:]) #此过程寻找到的答案没有考虑初始位置位置为 0 的情况
return
for i in range(n):
nums[row]=i
if chick(nums,row):
dfs(nums,row+1)
n=int(input())
list1=[]
for i in range(n):
list1.append(list(map(eval,input().split())))
list2=[]
nums=[0 for i in range(n)]
count=0
dfs(nums,0) #此过程寻找到的答案没有考虑初始位置位置为 0 的情况
# print(list1) # [[1, 0, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
# print(list2) # [[1, 3, 0, 2], [2, 0, 3, 1]]
# print(n,len(list2)) # 4 2
list3=[]
for i in range(n): #在list2中寻找到的答案没有考虑初始位置位置为 0 的情况,故现在要寻找初始位置为 0 的答案
for j in range(len(list2)):
if list1[i][list2[j][i]]==0: #list1为 0的位置,list2不可以为 0
list3.append(list2[j])
for i in list3: #删除初始位置为 0 的答案,剩下的就是真正的答案
list2.remove(i)
for i in range(len(list2)): #两个答案的每一行为 0 的位置都不一样才可以组成一个黑、白皇后都可以放置的答案
for j in range(len(list2)):
k=0
flag1=True
flag2=False
while k<n and j>i and j<len(list2):
flag2=True
if list2[i][k]==list2[j][k]:
flag1=False
break
k+=1
if flag1 and flag2:
count+=2 #因为每个答案黑、白皇后的位置都可以互换,所以找到一个“两个答案的每一行为 0 的位置都不一样”的答案相当于增加两种方法
print(count)
java解法:
// 100分
//先寻找白皇后的位置,再寻找黑皇后的位置
import java.util.Scanner;
public class Main {
private static int[][] arr;
private static int[] arr1;
private static int[] arr2;
private static int n;
private static int count=0;
public static void main(String[] args){
Scanner scan=new Scanner(System.in);
n=scan.nextInt();
scan.nextLine();
String[] arr3;
arr=new int[n][n];
arr1=new int[n];
arr2=new int[n];
for(int i=0;i<n;i++){
arr3=scan.nextLine().split(" ");
for(int j=0;j<n;j++){
arr[i][j]=Integer.parseInt(arr3[j]);
}
}
dfsWhite(arr1,0);
System.out.println(count);
}
public static Boolean checkWhite(int[] arr1,int row){
if(arr[row][arr1[row]]==1){
for(int i=0;i<row;i++){
if(Math.abs(arr1[i]-arr1[row])==Math.abs(i-row) || arr1[i]==arr1[row]){
return false;
}
}
return true;
}
return false;
}
public static Boolean checkBlack(int[] arr2,int row){
if(arr[row][arr2[row]]==1 && arr1[row]!=arr2[row]){
for(int i=0;i<row;i++){
if(Math.abs(arr2[i]-arr2[row])==Math.abs(i-row) || arr2[i]==arr2[row]){
return false;
}
}
return true;
}
return false;
}
public static void dfsWhite(int[] arr1,int row){
if(row==n){
dfsBlack(arr2,0);
return;
}
for(int i=0;i<n;i++){
arr1[row]=i;
if(checkWhite(arr1,row)){
dfsWhite(arr1,row+1);
}
}
}
public static void dfsBlack(int[] arr2,int row){
if(row==n){
count++;
return;
}
for(int i=0;i<n;i++){
arr2[row]=i;
if(checkBlack(arr2,row)){
dfsBlack(arr2,row+1);
}
}
}
}