利用oracle的递归cte

var n number
exec :n:=8
with p(p,r,c,w)
as(select level,ceil(level/:n),mod(level-1,:n)+1,power(2,level-1) from dual connect by level<=:n*:n)
,w as(select q.p,q.r,q.c,q.w,sum(p.w)sw from p,p q where
p.r=q.r or p.c=q.c or q.r-q.c=p.r-p.c or q.r+q.c=p.r+p.c
group by q.p,q.r,q.c,q.w)
,b(board, n_queens,w)as(
    SELECT lpad('-',p-1,'-')||'*', 1 ,w
      FROM p where  p<=:N
    UNION all
    SELECT
      rpad(board,p-1,'-') || '*' ,N_queens + 1 ,b.w+w.w
      FROM b, w 
    WHERE n_queens <:N
      and p >n_queens*:N and p<=(n_queens+1)*:N
      and bitand(b.w,sw)=0
)
select rpad(board,:N*:N,'-')board from b where n_queens =:N
;

利用对称优化,第一行只取N/2个位置,然后把结果延Y轴翻转。如果N是奇数,那么第1行取(N+1)/2,第2行取(N-1)/2。因为1列只允许1个王后,所以从第2行起,中间列都是空的。

with p(p,r,c,w)
as(select level,ceil(level/:n),mod(level-1,:n)+1,power(2,level-1) from dual connect by level<=:n*:n)
,w as(select q.p,q.r,q.c,q.w,sum(p.w)sw from p,p q where
p.r=q.r or p.c=q.c or q.r-q.c=p.r-p.c or q.r+q.c=p.r+p.c
group by q.p,q.r,q.c,q.w)
,b(board, n_queens,w)as(
    SELECT lpad('-',p-1,'-')||'*', 1 ,w
      FROM p where  p<=(case mod(:N,2) when 0 then :N/2 else (:N+1)/2 end)
    UNION all
    SELECT
      rpad(board,p-1,'-') || '*' ,N_queens + 1 ,b.w+w.w
      FROM b, w 
    WHERE n_queens <:N
      and p >n_queens*:N and 
    p<=case when mod(:N,2)=1 and /*N_queens=1 and*/ b.w=power(2,(:N-1)/2) -- mid of row 1 is set
   then (n_queens+1)*:N-(:N+1)/2 
   else (n_queens+1)*:N end
      and bitand(b.w,sw)=0
),
hf as(select rpad(board,:N*:N,'-')board from b where n_queens =:N)
select * from hf
union all
select listagg(reverse(substr(board,(l-1)*:N+1,:N)))
within group(order by l) from hf a,(select level l from dual connect by level<=:N)b
group by board
;

运行时间减少1/3。