论坛首页 综合技术论坛

用 Python 秒掉八皇后问题!

浏览 43137 次
该帖已经被评为良好帖
作者 正文
   发表时间:2007-08-10  
hax 写道
我来个js版本:
function queen(x, y) {
	if (x < y || y < 1) throw Error();
	
	var r = [];
	
	if (y == 1) {
		for (var i = 0; i < x; i++) {
			r.push([i]);
		}
		return r;
	}
	
	var r0 = queen(x, y - 1);
	for (var r0n = r0.length, r0i = 0; r0i < r0n; r0i++) {
		var a = r0[r0i];
		var n = a.length;
		var p = [];
		for (var i = 0, j = n; i < n; i++, j--) {
			p[a[i]] = true;
			p[a[i] + j] = true;
			p[a[i] - j] = true;
		}
		for (var i = 0; i < x; i++) {
			if (p[i]) continue;
			r.push(a.concat([i]));
		}
	}
	return r;
}


代码风格不是函数式了。而变成命令式了。
0 请登录后投票
   发表时间:2007-09-21  
我也来个Ruby的

def check(e, i)
  e.each_with_index{ |x, index| 
    return false if x == i ||          # | 
        x + (e.length - index) == i || # \
        x - (e.length - index) == i    # /
  }
  return true
end

def queens(n, m = n)
  n, m = m, n if n < m
  return (0...n).collect { |i| [i] } if m == 1
  return queens(n, m -1).inject([]) { |s, e|
    0.upto(n - 1) { |i| s << e + [i] if check(e, i) }
    s
  }
end

p queens(8)
0 请登录后投票
   发表时间:2007-09-21  
还有楼主上面留的小问题

def convert(ary)
  s = []
  ary.each_with_index { |x, i| s << [i, x] }
  return s
end

def format(ary)
  convert(ary).collect { |x| "(#{x[0]}, #{x[1]})"  }.join(' ')
end

convert([2, 3, 4, 5]) # => [[0, 2], [1, 3], [2, 4], [3, 5]]
format([2, 3, 4, 5]) # => "(0, 2) (1, 3) (2, 4) (3, 5)"
0 请登录后投票
   发表时间:2007-11-29  
问句题外话:
函数式编程的力量就在于抽象等级的空前提高
这句话是楼主自己的还是引用的?我喜欢
0 请登录后投票
   发表时间:2007-11-29  
zenny 写道
问句题外话:
函数式编程的力量就在于抽象等级的空前提高
这句话是楼主自己的还是引用的?我喜欢

应该是《计算机程序的构造和解释》这本书上的,但我好像没找到。
反正差不多就是SICP里面的那个意思。SICP成天唠叨抽象来抽象去,就是没怎么提OOP。
0 请登录后投票
   发表时间:2007-12-18  
给一个 haskell 版本:

import Control.Monad
import Control.Monad.Writer
import Data.List

diagonal (x1,y1) (x2,y2) = x1 + y1 == x2 + y2
                        || x1 - y1 == x2 - y2

nqueens n = execWriter $ f [1..n] 1 []
    where f [] _ ps = tell [ps]
          f cs r ps = forM_ cs $ \c ->
                          unless (any (diagonal (r,c)) ps) $
                              f (delete c cs) (r + 1) ((r,c):ps)
main = print $ nqueens 4

执行结果:

[[(4,3),(3,1),(2,4),(1,2)],[(4,2),(3,4),(2,1),(1,3)]]

这个结果返回了所有可能的结果,如果这个N很大的话,将耗费很长的时间!
hoho~ Haskell中完全没问题,我们只要一个大的结果中的第一项: Haskell中的惰性计算

main = print $ head $ nqueens 8
这样,将只得到一个结果然后就停止计算,haskell的表示 Lazy 的。

对程序的具体解释
求解一个N皇后问题,问题本身不描述了,地球人都知道。
面对一个N×N的棋盘,我们一行行放,开始我们有N个列可以放棋子,按照规则(互相不能攻击)我们一行行的放下去,可用的列便逐渐减少,而我们的行数在增加,已经摆放的棋子也在增加。直到全部放完N行,也就是说没有空余的列了。

对于放棋子的操作,我们称为 f 函数,有三个参数: 当前剩余的列,当前行数,已经摆放的棋子的位置。
第一种情况: 当前的剩余列空了,说明我们都摆放完了,那么我们得到一个结果并 tell 出去:(相当于 python中的 yield)
f [] _ ps = tell [ps]
第二种情况: 从剩余的列中一个个都试验,看看能不能放下棋子。对每个位置(r, c) ,除非它和任何一个已有的棋子冲突,否则我们将得到一个合适的位置。对这个位置,递归调用f 来检测, 把c从剩余列中删除,行数加1,把(r,c)位置记录到ps中。(最近有老年痴呆症装,唠叨见多)
f cs r ps = forM_ cs $ \c ->
unless (any (diagonal (r,c)) ps) $
f (delete c cs) (r + 1) ((r,c):ps)

求N皇后,就是调用下 f [1..n] 1 [] ,把 f tell我们的结果抽取出来。
nqueens n = execWriter $ f [1..n] 1 []

整个程序基本上相当于口语的翻译。 FP语言都说难理解,我却找不到比这更容易理解的算法描述了。
0 请登录后投票
   发表时间:2008-03-28  
直接出自ML
0 请登录后投票
   发表时间:2008-05-19  
弱弱的问下
 “ran ≠ x 很好理解,就是不为同一列;|ran - x| ≠ y + 1 则意味着左右不在同一斜线上。”

|ran - x| ≠ y + 1 则意味着左右不在同一斜线上。”
这一句我一直理解不了。。
不是|ran - x|== |y的相差值|么?
0 请登录后投票
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics