51. N-Queens

题目:

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

Given an integer n, return all distinct solutions to the n-queens puzzle.

Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.

For example,
There exist two distinct solutions to the 4-queens puzzle:

[
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]
 代码:
N皇后问题,经典问题,想想应该用递归来做,逻辑想想也不复杂,但就是实现起来总觉得好困难!
最近在学习python的生成器yield,用生成器可以很优雅的实现这个问题:
生成器并不会一次返回所有结果,而是每次遇到yield关键字后返回相应结果,并保留函数当前的运行状态,等待下一次的调用。
yield类似于普通函数执行中的return,不同的是会记录当前函数运行状态和结果,下次接着该状态执行。代码参考Magnus Lie Hetland的《python基础教程》第二版:
#encoding:utf-8
import random
class Solution(object):
    #判断新增位置是否与之前位置冲突
    #state用元组(tupe)保存之前换后的位置,例如0-3行皇后的位置保存为(1,3,0)
    #nextX代表下一个皇后的水平位置,和state的所有元素比较
    #保证不在一条线上(X坐标相同)且不在一个对角线上(Y坐标位置的差不等于X坐标位置的差),代码中:X坐标位置的差 not in(0, nextY-i)  
    def conflict(self, state, nextX):
        nextY = len(state)
        for i in range(nextY):
            if abs(state[i]-nextX) in (0, nextY-i):
                return True
        return False
    
    #输入棋盘大小num和当前皇后位置状态state
    #用conflict判断下一行皇后的位置pos是否与state中的皇后位置冲突
    #冲突就放弃这个迭代分支
    #不冲突继续:分两种情况分支:
    # 1.下一行皇后是最后一行的皇后,不冲突的话就保存结果,无需迭代
    # 2.下一行皇后不是最后一行皇后,不冲突的话迭代调用该函数(queens()),迭代变量唯一区别是state的中增加当前皇后的位置,从而用来判断下一行皇后
    #注意生成器的使用:
    #生成器并不会一次返回所有结果,而是每次遇到yield关键字后返回相应结果,并保留函数当前的运行状态,等待下一次的调用。
    def queens(self, num=8,state=()):
        for pos in range(num):
            if not self.conflict(state, pos):
                if len(state) == num-1:
                    print ('state: ',state)
                    #print ('last pos: ',pos)
                    yield(pos, )
                else:
                    for result in self.queens(num, state + (pos,)):
                        #print ('state: ',state)
                        #print ('pos: ',pos)
                        #print ('result: ',result)
                        yield(pos, )+result

    #该函数仅仅为了按题目要求格式化输出结果
    def prettyprint(self, one_way):
        result_list=[]
        def line(pos, length = len(one_way)):
            return ('.'*(pos) + 'Q' + '.'*(length-pos-1))
        for pos in one_way:
            result_list.append(line(pos))
        return result_list       
    
    def solveNQueens(self, n):
        """
        :type n: int
        :rtype: List[List[str]]
        """
        if(n==1): return [["Q"]]
        elif(n<=3): return []
        res_list = []
        solution = list(self.queens(n))
        #for i in solution:res_list.append(self.prettyprint(i))
        for i in solution:res_list.append(i)
        #print (res_list)
        #print (self.prettyprint(list(self.queens(n))[0]))
        return res_list
    
   
if __name__=="__main__":
    #print (list(queens(8)))
    #prettyprint(random.choice(list(queens(8))))
    a = Solution()
    print (a.solveNQueens(4))
   
运行结果:
   
当然,该算法不是解决八皇后问题的最优解,必定效率不高:
关于更多优秀解法,可以自行google。

 

第一道解决的LeetCode中Hard难度问题,基本上copy了书中的方法。不过通过逐句的分析学习,还是受益匪浅。

posted @ 2016-10-18 14:44  PolarBearInterest  阅读(198)  评论(0编辑  收藏  举报