八皇后问题

16 篇文章 0 订阅
3 篇文章 0 订阅

前言

中国有一句古话,叫做“不撞南墙不回头",生动的说明了一个人的固执,有点贬义,但是在软件编程中,这种思路确是一种解决问题最简单的算法,它通过一种类似于蛮干的思路,一步一步地往前走,每走一步都更靠近目标结果一些,直到遇到障碍物,我们才考虑往回走。然后再继续尝试向前。通过这样的波浪式前进方法,最终达到目的地。当然整个过程需要很多往返,这样的前进方式,效率比较低下。此为递归算法。接下来的这个问题也和可以用递归算法解决。

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。

该问题是国际西洋棋棋手马克斯·贝瑟尔于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解决就很调皮, 几行搞定 …

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值