问题描述:
n
皇后问题研究的是如何将n
个皇后放置在n×n
的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数n
,返回 n
皇后不同的解决方案的数量。
示例:
输入: 4
输出: 2
解释: 4 皇后问题存在如下两个不同的解法。
[
[".Q…", // 解法 1
“…Q”,
“Q…”,
“…Q.”],
["…Q.", // 解法 2
“Q…”,
“…Q”,
“.Q…”]
]
问题分析:
该有多无聊,才去重新写一个n年前的算法题目?这个第一次见是上数据结构课,递归的那一章,哈哈。总结一下:
(1)方法是回溯法,具体就是深度优先搜索。
(2)我们一行一行的放下去,在放的过程中,判断这个位置是否可以放?可以就放,不可以就进行下一个位置,到头了,就回溯到上一行。
(3)放完n个皇后,就计数一次。直到结束。
Python3实现:
方法一,递归的方法:
# @Time :2019/02/02
# @Author :LiuYinxing
# 回溯法,深度优先
class Solution:
def totalNQueens(self, n):
"""
:type n: int
:rtype: int
"""
cnt, q = 0, [None] * n # cnt 用计数,q用于已经放的位置,例如q[2]=3 表示第3行的放到了第4个位置
def dfs(k, n):
nonlocal cnt # 使用外部变量
if k == n:
cnt += 1
else:
for j in range(n): # 一行一行的进行深度搜索
if self.place(k, j, q):
q[k] = j
dfs(k+1, n)
dfs(0, n)
return cnt
def place(self, k, j, q): # 判断该位置是否可以放一个棋子
for i in range(k):
if q[i] == j or abs(q[i]-j) == abs(i-k): # 不同列,不同斜线
return 0
return 1
if __name__ == '__main__':
solu = Solution()
print(solu.totalNQueens(4))
方法二,栈的方法(这段C++代码是很久之前学数据结构时候的,这里只提供一个思路):
#include <iostream>
#include <cmath>
using namespace std;
#define MaxSize 100
int count=1; //记录解个数
struct StType //定义顺序栈类型
{
int data[MaxSize]; //data[i]存放第i个皇后的列号
int top; //栈顶指针
};
bool place(StType st,int i,int j) //测试(i,j)是否与1~i-1皇后有冲突
{
int k=1;
if (i==1)
return true; //放第一个皇后时没有冲突
while (k<=i-1) //j=1到k-1是已放置了皇后的列
{
if ((st.data[k]==j) || (abs(j-st.data[k])==abs(k-i)))
return false;
k++;
}
return true;
}
void queen(int n) //求解n皇后问题
{
int i,j,k;
bool find;
StType st; //定义栈st
st.top=0; //初始化栈顶指针
st.top++; //将(1,1)进栈
st.data[st.top]=1;
while (st.top>0) //栈不空时循环
{
i=st.top; //当前皇后为第i个皇后
if (st.top==n) //所有皇后均放好,输出一个解
{
cout<<n<<"皇后问题第"<<count++<<"个解为:";
for (k=1;k<=st.top;k++)
cout<<"("<<k<<" "<<st.data[k]<<")"<<" ";
cout<<endl;
}
find=false;
for (j=1;j<=n;j++)
if (place(st,i+1,j)) //在i+1行找到一个放皇后的位置(i+1,j)
{
st.top++;
st.data[st.top]=j; //在i+1行找到一个放皇后的位置(i+1,j)并进栈
find=true; //如果为真,则返回继续,再此查找
break;
}
if (find==false) //在i+1行找不到放皇后的位置,回溯
{
while (st.top>0)
{
if (st.data[st.top]==n) //退栈
st.top--;
for (j=st.data[st.top]+1;j<=n;j++) //在i行查找下一个位置
if (place(st,st.top,j))
{
st.data[st.top]=j;
break;
}
if (j>n) //当前皇后在本行没有可放的位置
st.top--; //退栈
else //本行找到一个位置后退出回溯
break;
}
}
}
}
int main()
{
int n; //n存放实际皇后个数
cout<<"温馨提示输入的数尽量不要大于15否则CPU会累死的。"<<endl;
cout<<"请输入N皇后问题的N(N<20)值:"<<endl;
cin>>n;
if (n>20)
cout<<"N值太大,本程序无法为你求解。"<<endl;
else
{ cout<<n<<"皇后问题求解如下:"<<endl;
queen(n);
cout<<endl;
}
return 0;
}
声明: 总结学习,有问题或不当之处,可以批评指正哦,谢谢。