• No results found

The Eight Queens Problem

The problem of the eight queens is a well-known example of the use of trial-and-error methods and of backtracking algorithms. It was investigated by C .F. Gauss in 1850, but he did not completely solve it. This should not surprise anyone. After all, the characteristic property of these problems is that they defy analytic solution. Instead, they require large amounts of exacting labor, patience, and accuracy. Such algorithms have therefore gained relevance almost exclusively through the automatic computer, which possesses these properties to a much higher degree than people, and even geniuses, do.

The eight queens poblem is stated as follows (see also [3-4]): Eight queens are to be placed on a chess board in such a way that no queen checks against any other queen. Using the last schema of Sect. 3.4 as a template, we readily obtain the following crude version of a solution:

PROCEDURE Try(i: INTEGER); BEGIN

initialize selection of positions for i-th queen: REPEAT make next selection;

IF safe THEN SetQueen; IF i < 8 THEN Try(i+1);

IF not successful THEN RemoveQueen END END

END

UNTIL successful OR no more positions END Try

In order to proceed, it is necessary to make some commitments concerning the data representation. Since we know from the rules of chess that a queen checks all other figures lying in either the same column, row, or diagonal on the board, we infer that each column may contain one and only one queen, and that the choice of a position for the i th queen may be restricted to the i th column. The parameter i therefore becomes the column index, and the selection process for positions ranges over the eight possible values for a row index j.

There remains the question of representing the eight queens on the board. An obvious choice would again be a square matrix to represent the board, but a little inspection reveals that such a representation would lead to fairly cumbersome operations for checking the availability of positions. This is highly undesirable since it is the most frequently executed operation. We should therefore choose a data representation which makes checking as simple as possible. The best recipe is to represent as directly as possible that information which is truly relevant and most often used. In our case this is not the position of the queens, but whether or not a queen has already been placed along each row and diagonals. (We already know that exactly one is placed in each column k for 0 ≤ k < i). This leads to the following choice of variables:

VAR x: ARRAY 8 OF INTEGER; a: ARRAY 8 OF BOOLEAN; b, c: ARRAY 15 OF BOOLEAN where

xi denotes the position of the queen in the i th column; aj means "no queen lies in the j th row";

bk means "no queen occupies the k th /-diagonal; ck means "no queen sits on the k th \-diagonal.

We note that in a /-diagonal all fields have the same sums of their coordinates i and j, and that in a \- diagonal the coordinate differences i-j are constant. The appropriate solution is shown in the following program Queens. Given these data, the statement SetQueen is elaborated to

x[i] := j; a[j] := FALSE; b[i+j] := FALSE; c[i-j+7] := FALSE the statement RemoveQueen is refined into

a[j] := TRUE; b[i+j] := TRUE; c[i-j+7] := TRUE

and the condition safe is fulfilled if the field <i, j> lies in in a row and in diagonals which are still free. Hence, it can be expressed by the logical expression

a[j] & b[i+j] & c[i-j+7]

This completes the development of this algorithm, that is shown in full as Program 3.4. The computed solution is x = (1, 5, 8, 6, 3, 7, 2, 4) and is shown in Fig. 3.9.

Fig. 3.9. A solution to the Eight Queens problem PROCEDURE Try(i: INTEGER; VAR q: BOOLEAN);

VAR j: INTEGER; BEGIN j := 0;

REPEAT q := FALSE;

IF a[j] & b[i+j] & c[i-j+7] THEN x[i] := j;

a[j] := FALSE; b[i+j] := FALSE; c[i-j+7] := FALSE; IF i < 7 THEN

Try(i+1, q); IF ~q THEN

a[j] := TRUE; b[i+j] := TRUE; c[i-j+7] := TRUE END ELSE q := TRUE END END ; INC(j) UNTIL q OR (j = 8) END Try; PROCEDURE Queens;

VAR i: INTEGER; (*uses global writer W*) BEGIN

FOR i := 0 TO 7 DO a[i] := TRUE END ;

FOR i := 0 TO 14 DO b[i] := TRUE; c[i] := TRUE END ; Try(0,q);

FOR i := 0 TO 7 DO Texts.WriteInt(W, x[i], 4) END ; Texts.WriteLn(W)

END Queens.

Before we abandon the context of the chess board, the eight queens example is to serve as an illustration of an important extension of the trial-and-error algorithm. The extension is -- in general terms -- to find not only one, but all solutions to a posed problem.

The extension is easily accommodated. We are to recall the fact that the generation of candidates must progress in a systematic manner that guarantees no candidate is generated more than once. This property of the algorithm corresponds to a search of the candidate tree in a systematic fashion in which every node is visited exactly once. It allows -- once a solution is found and duly recorded -- merely to proceed to the next candidate delivered by the systematic selection process. The general schema is as follows:

PROCEDURE Try(i: INTEGER); VAR k: INTEGER; 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7

BEGIN

FOR k := 0 TO n-1 DO select k th candidate;

IF acceptable THEN record it;

IF i < n THEN Try(i+1) ELSE output solution END ; cancel recording

END END END Try

Note that because of the simplification of the termination condition of the selection process to the single term k = n, the repeat statement is appropriately replaced by a for statement. It comes as a surprise that the search for all possible solutions is realized by a simpler program than the search for a single solution. The extended algorithm to determine all 92 solutions of the eight queens problem is shown in Program 3.5. Actually, there are only 12 significantly differing solutions; our program does not recognize symmetries. The 12 solutions generated first are listed in Table 3.2. The numbers n to the right indicate the frequency of execution of the test for safe fields. Its average over all 92 solutions is 161.

PROCEDURE write; VAR k: INTEGER; BEGIN (*global writer W*)

FOR k := 0 TO 7 DO Texts.WriteInt(W, x[k], 4) END ; Texts.WriteLn(W)

END write;

PROCEDURE Try(i: INTEGER); VAR j: INTEGER;

BEGIN

FOR j := 1 TO 8 DO

IF a[j] & b[i+j] & c[i-j+7] THEN x[i] := j;

a[j] := FALSE; b[i+j] := FALSE; c[i-j+7] := FALSE; IF i < 7 THEN Try(i+1) ELSE write END ;

a[j] := TRUE; b[i+j] := TRUE; c[i-j+7] := TRUE END END END Try; PROCEDURE AllQueens; VAR i: INTEGER; BEGIN

FOR i := 0 TO 7 DO a[i] := TRUE END ;

FOR i := 0 TO 14 DO b[i] := TRUE; c[i] := TRUE END ; Try(0) END AllQueens. x1 x2 x3 x4 x5 x6 x7 x8 n 1 5 8 6 3 7 2 4 876 1 6 8 3 7 4 2 5 264 1 7 4 6 8 2 5 3 200 1 7 5 8 2 4 6 3 136 2 4 6 8 3 1 7 5 504 2 5 7 1 3 8 6 4 400 2 5 7 4 1 8 6 3 072 2 6 1 7 4 8 3 5 280 2 6 8 3 1 4 7 5 240 2 7 3 6 8 5 1 4 264

2 7 5 8 1 4 6 3 160

2 8 6 1 3 5 7 4 336

Table 3.2 Twelve Solutions to the Eight Queens Problem.