N-queens problem: Difference between revisions

m
→‎Python: Backtracking on permutations: Restored the original look
m (→‎Python: Niklaus Wirth algorithm: Revised one sentence)
m (→‎Python: Backtracking on permutations: Restored the original look)
(11 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 easily improved by using permutations and O(1) sets instead of O(n) lists and by avoiding the time- and space-consuming implicitunnecessary copy operations during recursion. An additional list ''x'' was added to record the solution. On a regular 8x8 board only 5,508 possible queen positions are examined.
<syntaxhighlight lang="python">def queens(ni: int, a: set):
if a: # set a is not empty
def queen(i: int) for j in a:
if a:i + #j setnot ain isb and i - j not emptyin c:
for b.add(i + j); inc.add(i a- j); x.copyappend(j):
ifyield from queens(i + j1, not in b and ia - {j not in c:})
b.remove(i + j); ac.remove(i - j); x.pop()
else:
b.add(i + j)
yield c.add(i - j)x
x.append(j)
yield from queen(i + 1)
a.add(j)
b.remove(i + j)
c.remove(i - j)
x.pop()
else:
yield x
 
a = set(range(n))
b = set()
c = set()
x = []
yield from queen(0)
 
b = set(); c = set(); x = []
 
for solution in queens(0, set(range(8))):
print(solution)</syntaxhighlight>
 
===Python: backtrackingBacktracking 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