前言
中国有一句古话,叫做“不撞南墙不回头",生动的说明了一个人的固执,有点贬义,但是在软件编程中,这种思路确是一种解决问题最简单的算法,它通过一种类似于蛮干的思路,一步一步地往前走,每走一步都更靠近目标结果一些,直到遇到障碍物,我们才考虑往回走。然后再继续尝试向前。通过这样的波浪式前进方法,最终达到目的地。当然整个过程需要很多往返,这样的前进方式,效率比较低下。此为递归算法。接下来的这个问题也和可以用递归算法解决。
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。
该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法?
详情查看Leetcode-52题
具体回朔法不在此详解,只列出几种解决答案。本人建议一定去了解回朔法,否则看答案没有太大意义。
第一种是scala语言
object EightQueen extends App{
val queenArray = new Array[Int](8)
var num = 0
def printqueen(){
for(i <- 0.until(8);j <- 0.until(8)){
if(j == queenArray(i)) print('*') else print('-')
if(j == 7) println();
}
}
def cango(x:Int,y:Int):Boolean={
for(i <- 0.until(x)){
if(queenArray(i) == y) return false;
if(i + queenArray(i) == x + y) return false;
if(i - queenArray(i) == x - y) return false;
}
true
}
def queen(x:Int){
for(i <- 0.until(8)){
if(cango(x,i)){
queenArray(x) = i
if(x == 7){
num += 1
println(num)
printqueen()
queenArray(x) = (i + 1) % 8
return
}
queen(x + 1)
}
}
}
queen(0)
}
第二种是java语言
public class Queen8 {
public static int num = 0; //累计方案总数
public static final int MAXQUEEN = 8;//皇后个数,同时也是棋盘行列总数
public static int[] cols = new int[MAXQUEEN]; //定义cols数组,表示8列棋子摆放情况
public Queen8() {
//核心函数
getArrangement(0);
System.out.print("/n");
System.out.println(MAXQUEEN+"皇后问题有"+num+"种摆放方法。");
}
public void getArrangement(int n){
//遍历该列所有不合法的行,并用rows数组记录,不合法即rows[i]=true
boolean[] rows = new boolean[MAXQUEEN];
for(int i=0;i<n;i++){
rows[cols[i]]=true;
int d = n-i;
if(cols[i]-d >= 0)rows[cols[i]-d]=true;
if(cols[i]+d <= MAXQUEEN-1)rows[cols[i]+d]=true;
}
for(int i=0;i<MAXQUEEN;i++){
//判断该行是否合法
if(rows[i])continue;
//设置当前列合法棋子所在行数
cols[n] = i;
//当前列不为最后一列时
if(n<MAXQUEEN-1){
getArrangement(n+1);
}else{
//累计方案个数
num++;
//打印棋盘信息
printChessBoard();
}
}
}
public void printChessBoard(){
System.out.print("第"+num+"种走法 /n");
for(int i=0;i<MAXQUEEN;i++){
for(int j=0;j<MAXQUEEN;j++){
if(i==cols[j]){
System.out.print("0 ");
}else
System.out.print("+ ");
}
System.out.print("/n");
}
}
public static void main(String args[]){
Queen8 queen = new Queen8();
}
}
第三种是python语言(也是最喜欢用的语言)
算法思想
- 创建一个ret=[],把所有成功的state都包进去,最后求ret。
- 关键就是state怎么求。
- 如果有八个子,我肯定每个位置都放一下,所以最外层应该是for循环
放之前,我先想想这个位置能不能放,判断的函数用conflict()来表示。- 如果能放的话,我就放下来。
- 看是不是最后一个子,如果不是,那么我这次的子后面的所有能放的都传给我。
- 如果是最后一个子,那么我就这个结果yield回去。
def conflict(state,nextx):
"""定义冲突函数,state为元组,nextx为下一个皇后的水平位置,nexty为下一个皇后的垂直位置"""
nexty = len(state)
for i in range(nexty):
if abs(state[i] - nextx) in (0, nexty-i): # 若下一个皇后和前面的皇后列相同或者在一条对角线上,则冲突
return True
return False
def queens(num=8, state=()):
"""八皇后问题,这里num表示规模"""
for pos in range(num):
if not conflict(state,pos): # 位置不冲突
if len(state) == num - 1: # 若是最后一个皇后,则返回该位置
yield (pos, )
else: # 若不是最后一个皇后,则将该位置返回到state元组并传给后面的皇后
for result in queens(num,state + (pos,)):
yield (pos, ) + result
是不是用Python解决就很调皮, 几行搞定 …