【题目描述】
有一个N*N的矩阵棋盘和N个棋子,现在需要将N个棋子按要求放置在矩阵方格中。
要求:
1、任意两颗棋子不能在同一行
2、任意两个棋子不能在同一列
3、任意两个棋子不能在同一对角线上(下面的红线都是对角线)
根据以上要求,问N个棋子放置到N*N矩阵中有多少种放置方案?
【输入描述】
输入一个正整数N(1<N<11),表示N*N的矩阵方格和N个棋子数量。
【输出描述】
输出N个棋子按要求放置到N*N的矩阵中,有多少种放置方案?
【解题思路】
这要用到dfs来做
首先放置一颗棋子,从第一行开始放置,放置后该行就不能放置其他棋子来,然后每一行放的棋子通过一列一列的方式去检查是否可以放置,跳转到下一行,依次类推,如果下一行都标记不能放置的话,则回溯到上面的操作,依次进行向下标记;如果标记到最后一行,则统计次数,再清空矩阵,直到全部走完。
因为执行的每一趟操作都是类似的,所以可以增加一个递归来计算
设置一个函数,递归的开始条件从第一行开始,可以放置,则跳转到下一行。。。
递归的退出条件是:最后一行,或者下一行没有可以走到点的时候退出
图解
1.首先在第一行第一列放置一个棋子,将所在的对角线,行和列都标记不能放置。
2.接着跳转到第二行,重复第一步的操作
3.当跳转到下一行的时候,发现都标记了不能放置,则表示无法走通,这一趟不行,回溯到上一步,清空第二部的所有标记,进行另外一个点的放置。
4.接着再跳转到第三行,再进行标记,标记后发现第四行 也以及不可放置,所以这条路也走不通,则清空,回溯到上面新的点再进行操作,以此类推。直到找到能标记到最后一行的点,计数。
直到走到这步才算完整的一条路,得出第一条摆放方式
【代码运算】
n=4
#用来表示放置的位置(下标表示第几行,数值表示第几列)
# ->place[1]=2 表示在第二行第三列标记了数
place = [0 for _ in range(n)]
#用于表示第n列是否被标记 -> flag[1]=1 表示第2列被标记为1
flag=[0 for _ in range(n)]
#表示对角线是否被标记
d1=[0 for _ in range(2*n-1)]#上对角线 行加上列
d2=[0 for _ in range(2*n-1)]#下对角线 行减列加n减1
#计数
count=0
def search(row):#行
global count #标记全局变量
for col in range(n):
if flag[col]==0 and d1[row+col]==0 and d2[row-col+n-1]==0:# 0表示没有被标记
place[row] = col #在第row行第col列标记
#列,对角线标记不能X
flag[col]=1
d1[row+col]=1
d2[row-col+n-1]=1
#如果不是最后一行,继续寻找
if row<n-1:
search(row+1)
else:
count+=1
#最后一行执行结束,清空,继续寻找下一个
flag[col]=0
d1[row+col]=0
d2[row-col+n-1]=0
search(0) #从第一行开始寻找
print(count) #2
上对角线——一共有2*n-1条 可以观察到,行加列=对角线上的值
下对角线——也是2*n-1条,计算对角线上的值是——row-col+n-1
如果想要打印结果,只需要增加一个打印的函数,在每次统计次数时加一个打印即可
【运行代码】
n=4
#用来表示放置的位置(下标表示第几行,数值表示第几列)
# ->place[1]=2 表示在第二行第三列标记了数
place = [0 for _ in range(n)]
#用于表示第n列是否被标记 -> flag[1]=1 表示第2列被标记为1
flag=[0 for _ in range(n)]
#表示对角线是否被标记
d1=[0 for _ in range(2*n-1)]#上对角线 行加上列
d2=[0 for _ in range(2*n-1)]#下对角线 行减列加n减1
#计数
count=0
#打印函数
def printf(place):
#创建一个n行n列的矩阵
for i in range(n):
for j in range(n):
if place[i]==j:
print('*',end=' ')
else:
print('0',end=' ')
print() #每行换行
print() #每个矩阵换行
def search(row):#行
global count #标记全局变量
for col in range(n):
if flag[col]==0 and d1[row+col]==0 and d2[row-col+n-1]==0:# 0表示没有被标记
place[row] = col #在第row行第col列标记
#列,对角线标记不能X
flag[col]=1
d1[row+col]=1
d2[row-col+n-1]=1
#如果不是最后一行,继续寻找
if row<n-1:
search(row+1)
else:
count+=1
#打印
printf(place)
#最后一行执行结束,清空,继续寻找下一个
flag[col]=0
d1[row+col]=0
d2[row-col+n-1]=0
search(0) #从第一行开始寻找
print(count) #2
【运行结果】