蓝桥杯VIP试题 基础练习 2n皇后问题(python解法+java解法)

蓝桥杯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);
            }
        }

    }


}






  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

itmengge

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值