N-queens problem: Difference between revisions

m
→‎Python: Backtracking on permutations: Restored the original look
m (→‎Python: Niklaus Wirth algorithm: Added a more optimized version.)
m (→‎Python: Backtracking on permutations: Restored the original look)
 
(13 intermediate revisions by 2 users not shown)
Line 11,360:
 
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<syntaxhighlight lang="phix">
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
with javascript_semantics
<span style="color: #000080;font-style:italic;">--
--
-- demo\rosetta\n_queens.exw
-- demo\rosetta\n_queens.exw
-- =========================
-- =========================
--</span>
--
<span style="color: #004080;">sequence</span> <span style="color: #000000;">co</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- columns occupied
sequence co, -- columns occupied
-- (ro is implicit)</span>
-- (ro is implicit)
<span style="color: #000000;">fd</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- forward diagonals</span>
fd, -- forward diagonals
<span style="color: #000000;">bd</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- backward diagonals</span>
bd, <span style="color: #000000;">board</span> -- backward diagonals
board
<span style="color: #004080;">atom</span> <span style="color: #000000;">count</span>
atom count
<span style="color: #008080;">procedure</span> <span style="color: #000000;">solve</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">row</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">N</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">show</span><span style="color: #0000FF;">)</span>
procedure solve(integer row, integer N, integer show)
<span style="color: #008080;">for</span> <span style="color: #000000;">col</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">N</span> <span style="color: #008080;">do</span>
for col=1 to N do
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">co</span><span style="color: #0000FF;">[</span><span style="color: #000000;">col</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
if not co[col] then
<span style="color: #004080;">integer</span> <span style="color: #000000;">fdi</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">col</span><span style="color: #0000FF;">+</span><span style="color: #000000;">row</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span>
integer fdi = col+row-1,
<span style="color: #000000;">bdi</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">row</span><span style="color: #0000FF;">-</span><span style="color: #000000;">col</span><span style="color: #0000FF;">+</span><span style="color: #000000;">N</span>
bdi = row-col+N
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">fd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">fdi</span><span style="color: #0000FF;">]</span>
if not fd[fdi]
<span style="color: #008080;">and</span> <span style="color: #008080;">not</span> <span style="color: #000000;">bd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">bdi</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
and not bd[bdi] then
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">row</span><span style="color: #0000FF;">][</span><span style="color: #000000;">col</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'Q'</span>
board[row][col] = 'Q'
<span style="color: #000000;">co</span><span style="color: #0000FF;">[</span><span style="color: #000000;">col</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
co[col] = true
<span style="color: #000000;">fd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">fdi</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
fd[fdi] = true
<span style="color: #000000;">bd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">bdi</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
bd[bdi] = true
<span style="color: #008080;">if</span> <span style="color: #000000;">row</span><span style="color: #0000FF;">=</span><span style="color: #000000;">N</span> <span style="color: #008080;">then</span>
if row=N then
<span style="color: #008080;">if</span> <span style="color: #000000;">show</span> <span style="color: #008080;">then</span>
if show then
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)&</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span>
puts(1,join(board,"\n")&"\n")
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'='</span><span style="color: #0000FF;">,</span><span style="color: #000000;">N</span><span style="color: #0000FF;">)&</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span styleputs(1,repeat('=',N)&"color: #008080;\n">if</span>)
end if
<span style="color: #000000;">count</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style count +="color: #008080;">else</span>1
else
<span style="color: #000000;">solve</span><span style="color: #0000FF;">(</span><span style="color: #000000;">row</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">N</span><span style="color: #0000FF;">,</span><span style="color: #000000;">show</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>solve(row+1,N,show)
end if
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">row</span><span style="color: #0000FF;">][</span><span style="color: #000000;">col</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'.'</span>
board[row][col] = '.'
<span style="color: #000000;">co</span><span style="color: #0000FF;">[</span><span style="color: #000000;">col</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
co[col] = false
<span style="color: #000000;">fd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">fdi</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
fd[fdi] = false
<span style="color: #000000;">bd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">bdi</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
bd[bdi] = false
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
end procedure
<span style="color: #008080;">procedure</span> <span style="color: #000000;">n_queens</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">N</span><span style="color: #0000FF;">=</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">show</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
procedure n_queens(integer N=8, integer show=1)
<span style="color: #000000;">co</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">N</span><span style="color: #0000FF;">)</span>
co = repeat(false,N)
<span style="color: #000000;">fd</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">N</span><span style="color: #0000FF;">*</span><span style="color: #000000;">2</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
fd = repeat(false,N*2-1)
<span style="color: #000000;">bd</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">N</span><span style="color: #0000FF;">*</span><span style="color: #000000;">2</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
bd = repeat(false,N*2-1)
<span style="color: #000000;">board</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">N</span><span style="color: #0000FF;">),</span><span style="color: #000000;">N</span><span style="color: #0000FF;">)</span>
board = repeat(repeat('.',N),N)
<span style="color: #000000;">count</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
count = 0
<span style="color: #000000;">solve</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">N</span><span style="color: #0000FF;">,</span><span style="color: #000000;">show</span><span style="color: #0000FF;">)</span>
solve(1,N,show)
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%d queens: %d solutions\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">N</span><span style="color: #0000FF;">,</span><span style="color: #000000;">count</span><span style="color: #0000FF;">})</span>
printf(1,"%d queens: %d solutions\n",{N,count})
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
end procedure
<span style="color: #008080;">for</span> <span style="color: #000000;">N</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()=</span><span style="color: #004600;">JS</span><span style="color: #0000FF;">?</span><span style="color: #000000;">12</span><span style="color: #0000FF;">:</span><span style="color: #000000;">14</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
for N=1 to iff(platform()=JS?12:14) do
<span style="color: #000000;">n_queens</span><span style="color: #0000FF;">(</span><span style="color: #000000;">N</span><span style="color: #0000FF;">,</span><span style="color: #000000;">N</span><span style="color: #0000FF;"><</span><span style="color: #000000;">5</span><span style="color: #0000FF;">)</span>
n_queens(N,N<5)
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end for
<!--</syntaxhighlight>-->
</syntaxhighlight>
{{out}}
<pre>
Line 12,841 ⟶ 12,842:
for solution in queens(8, 0, [], [], []):
print(solution)</syntaxhighlight>
The algorithm can be slightlyeasily improved by using permutations and O(1) sets instead of O(n) lists. Butand thisby makesavoiding theunnecessary algorithmcopy aoperations bitduring harderrecursion. toAn read, since theadditional list ''x'' has to bewas added to record the solution. On a regular 8x8 board only 5,508 possible queen positions are examined.
<syntaxhighlight lang="python">def queens(i: int, a: set, b: set, c: set, x: list):
if a: # set a is not empty
for j in a:
if i + j not in b and i - j not in c:
yield from queensb.add(i + 1, a - {j}, b | {i + j},); c | {.add(i - j},); x + [.append(j])
yield from queens(i + 1, a - {j})
b.remove(i + j); c.remove(i - j); x.pop()
else:
yield x
 
 
forb solution in queens(0,= set(range(8)),; set(),c = set(),; x = []):
for solution in queens(0, set(range(8))):
print(solution)</syntaxhighlight>
However, because these examples are intended for educational purposes, they are not optimized for resources or speed. The next example shows a more optimized solution that also requires less space on the stack.
<syntaxhighlight lang="python">def queens(n: int):
def queen(i: int):
if a: # set a is not empty
for j in a.copy():
if i + j not in b and i - j not in c:
a.remove(j)
b.add(i + j)
c.add(i - j)
x.append(j)
yield from queen(i + 1)
a.add(j)
b.remove(i + j)
c.remove(i - j)
x.pop()
else:
yield x
 
===Python: Backtracking on permutations===
a = set(range(n))
b = set()
c = set()
x = []
yield from queen(0)
 
 
for solution in queens(8):
print(solution)</syntaxhighlight>
 
===Python: backtracking on permutations===
Queens positions on a n x n board are encoded as permutations of [0, 1, ..., n]. The algorithms consists in building a permutation from left to right, by swapping elements of the initial [0, 1, ..., n], recursively calling itself unless the current position is not possible. The test is done by checking only diagonals, since rows/columns have by definition of a permutation, only one queen.
 
This is initially a translation of the Fortran 77 solution. The solutions are returned as a generator, using the "yield from" functionality of Python 3.3, described in [https://www.python.org/dev/peps/pep-0380/ PEP-380]. On a regular 8x8 board only 5,508 possible queen positions are examined.
 
<syntaxhighlight lang="python">def queens(n: int):
The solutions are returned as a generator, using the "yield from" functionality of Python 3.3, described in [https://www.python.org/dev/peps/pep-0380/ PEP-380].
 
def sub(i: int):
<syntaxhighlight lang="python">def queens(n):
a = list(range( if i < n)):
up = [True]*(2*n - 1)
down = [True]*(2*n - 1)
def sub(i):
if i == n:
yield tuple(a)
else:
for k in range(i, n):
j = a[k]
p =if b[i + j] and c[i - j]:
q = i - j + n - 1
if up[p] and down[q]:
up[p] = down[q] = False
a[i], a[k] = a[k], a[i]
b[i + j] = c[i - j] = False
yield from sub(i + 1)
upb[pi + j] = downc[qi - j] = True
a[i], a[k] = a[k], a[i]
else:
yield a
 
a = list(range(n))
b = [True] * (2 * n - 1)
c = [True] * (2 * n - 1)
yield from sub(0)
 
 
#Count solutions for n=8:
sum(1 for p in queens(8)) # count solutions
92</syntaxhighlight>
 
The preceding function does not enumerate solutions in lexicographic order, see [[Permutations#Recursive implementation]] for an explanation. The following does, but is almost 50% slower, because the exchange is always made (otherwise, restoring the loopstate to shiftof the array aafter bythe one place wouldloop notwouldn't work). On a regular 8x8 board only 5,508 possible queen positions are examined.
 
However, it may be interesting to look at the first solution in lexicographic order: for growing n, and apart from a +1 offset, it gets closer and closer to the sequence [http://oeis.org/A065188 A065188] at OEIS. The first n for which the first solutions differ is n=26.
 
<syntaxhighlight lang="python">def queens_lex(n: int):
 
a = list(range(n))
updef = [True]*sub(2*n -i: 1int):
down = [True]*(2*n - 1)if i < n:
def sub(i):
if i == n:
yield tuple(a)
else:
for k in range(i, n):
j = a[k]
a[i], a[k] = a[k], a[i]
if b[i + j] =and ac[i - j]:
p = b[i + j] = c[i - j] = False
q = i - j + n - 1
if up[p] and down[q]:
up[p] = down[q] = False
yield from sub(i + 1)
upb[pi + j] = downc[qi - j] = True
xa[i:(n - 1)], a[n - 1] = a[(i + 1):n], a[i]
for k in range(i + 1, n)else:
a[k - 1] =yield a[k]
 
a[n - 1] = x
a = list(range(n))
b = [True] * (2 * n - 1)
c = [True] * (2 * n - 1)
yield from sub(0)
 
 
next(queens(31))
([0, 2, 4, 1, 3, 8, 10, 12, 14, 6, 17, 21, 26, 28, 25, 27, 24, 30, 7, 5, 29, 15, 13, 11, 9, 18, 22, 19, 23, 16, 20)]
 
next(queens_lex(31))
([0, 2, 4, 1, 3, 8, 10, 12, 14, 5, 17, 22, 25, 27, 30, 24, 26, 29, 6, 16, 28, 13, 9, 7, 19, 11, 15, 18, 21, 23, 20)]
 
#Compare to A065188
305

edits