在壹個8×8的棋盤裏放置8個皇後,要求每個皇後兩兩之間不相"沖"(在每壹橫列豎列斜列只有壹個皇後)。
〖問題分析〗(聿懷中學呂思博)
這道題可以用遞歸循環來做,分別壹壹測試每壹種擺法,直到得出正確的答案。主要解決以下幾個問題:
1、沖突。包括行、列、兩條對角線:
(1)列:規定每壹列放壹個皇後,不會造成列上的沖突;
(2)行:當第I行被某個皇後占領後,則同壹行上的所有空格都不能再放皇後,要把以I為下標的標記置為被占領狀態;
(3)對角線:對角線有兩個方向。在同壹對角線上的所有點(設下標為(i,j)),要麽(i+j)是常數,要麽(i-j)是常數。因此,當第I個皇後占領了第J列後,要同時把以(i+j)、(i-j)為下標的標記置為被占領狀態。
2、數據結構。
(1)解數組A。A[I]表示第I個皇後放置的列;範圍:1..8
(2)行沖突標記數組B。B[I]=0表示第I行空閑;B[I]=1表示第I行被占領;範圍:1..8
(3)對角線沖突標記數組C、D。
C[I-J]=0表示第(I-J)條對角線空閑;C[I-J]=1表示第(I-J)條對角線被占領;範圍:-7..7
D[I+J]=0表示第(I+J)條對角線空閑;D[I+J]=1表示第(I+J)條對角線被占領;範圍:2..16
〖算法流程〗
1、數據初始化。
2、從n列開始擺放第n個皇後(因為這樣便可以符合每壹豎列壹個皇後的要求),先測試當前位置(n,m)是否等於0(未被占領):
如果是,擺放第n個皇後,並宣布占領(記得要橫列豎列斜列壹起來哦),接著進行遞歸;
如果不是,測試下壹個位置(n,m+1),但是如果當n<=8,m=8時,卻發現此時已經無法擺放時,便要進行回溯。
3、當n>;8時,便壹壹打印出結果。
〖優點〗逐壹測試標準答案,不會有漏網之魚。
〖參考程序〗queen.pas
----------------------------------------------------------------------------
programtt;
vara:array[1..8]ofinteger;
b,c,d:array[-7..16]ofinteger;
t,i,j,k:integer;
procedureprint;
begin
t:=t+1;
write(t,'');
fork:=1to8dowrite(a[k],'');
writeln;
end;
proceduretry(i:integer);
varj:integer;
begin
forj:=1to8do{每個皇後都有8種可能位置}
if(b[j]=0)and(c[i+j]=0)and(d[i-j]=0)then{判斷位置是否沖突}
begin
a:=j;{擺放皇後}
b[j]:=1;{宣布占領第J行}
c[i+j]:=1;{占領兩個對角線}
d[i-j]:=1;
ifi<8thentry(i+1){8個皇後沒有擺完,遞歸擺放下壹皇後}
elseprint;{完成任務,打印結果}
b[j]:=0;{回溯}
c[i+j]:=0;
d[i-j]:=0;
end;
end;
begin
fork:=-7to16do{數據初始化}
begin
b[k]:=0;
c[k]:=0;
d[k]:=0;
end;
try(1);{從第1個皇後開始放置}
end.
==========================================
這是N皇後問題,看看吧:
在N*N的棋盤上,放置N個皇後,要求每壹橫行每壹列,每壹對角線上均只能放置壹個皇後,問可能的方案及方案數。
const max=8;
var i,j:integer;
a:array[1..max] of 0..max; //放皇後數組
b:array[2..2*max] of boolean; // ‘/’對角線標誌數組}
c:array[-(max-1)..max-1] of boolean;// ‘\’對角線標誌數組}
col:array[1..max] of boolean; //列標誌數組}
total:integer; //統計總數}
procedure output; //這裏是輸出過程
var i:integer;
begin
write('No.':4,'[',total+1:2,']');
for i:=1 to max do write(a[i]:3);write(' ');
if (total+1) mod 2 =0 then writeln; inc(total);
end;
function ok(i,dep:integer):boolean; //判斷第dep行第i列可放否?
begin
ok:=false;
if ( b[i+dep]=true) and ( c[dep-i]=true) {and (a[dep]=0)} and
(col[i]=true) then ok:=true
end;
procedure try(dep:integer);
var i,j:integer;
begin
for i:=1 to max do //每壹行均有max種放法,對吧?xixi~~~~
if ok(i,dep) then begin
a[dep]:=i;
b[i+dep]:=false; // ‘/’對角線已放標誌
c[dep-i]:=false; // ‘\’對角線已放標誌
col[i]:=false; // 列已放標誌
if dep=max then output
else try(dep+1); // 遞歸下壹層
a[dep]:=0; //取走皇後,回溯
b[i+dep]:=true; //恢復標誌數組
c[dep-i]:=true;
col[i]:=true;
end;
end;
begin
for i:=1 to max do begin a[i]:=0;col[i]:=true;end;
for i:=2 to 2*max do b[i]:=true;
for i:=-(max-1) to max-1 do c[i]:=true;
total:=0;
try(1);
writeln('total:',total);
end.