八皇后回溯计算法研究
仔细看了下百度中的回溯法介绍,这是一种非常有用的算法,大概有两种模式,一种是遍历,一种是递归。
我把这两种方法都列出来了,按网上的说法,递归效率要比遍历快很多,我这里测试是一样的,可能是网络上那些遍历法根本没优化好吧,
多遍历了很多东西。
网上并没有Delphi的原代码,我综合了各种算法,将N阶皇后的算法一并写出来了。以下是原代码,希望有意研究的朋友跟我留言:
//工程文件:Queen8.dpr,以下代码在Delphi2010下编译通过。
program Queen8;
uses
Forms,
uQueen8 in 'uQueen8.pas' {fmQueen8};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TfmQueen8, fmQueen8);
Application.Run;
end.
//窗体单元文件:uQueen8.pas
unit uQueen8;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, Buttons,
Spin, ExtCtrls, StrUtils,DateUtils;
type
TfmQueen8 = class(TForm)
spn1: TSpinEdit;
btnRecurrence: TBitBtn;
mem1: TMemo;
lbl1: TLabel;
pnl1: TPanel;
mem2: TMemo;
btnGoThrough: TBitBtn;
procedure btnRecurrenceClick(Sender: TObject);
procedure btnGoThroughClick(Sender: TObject);
private
{ Private declarations }
Queen : array of Integer;
StyleCount : Integer;
public
{ Public declarations }
procedure OutputStyle(AStrs : TStrings; AQueen : array of Integer);
end;
var
fmQueen8: TfmQueen8;
implementation
{$R *.dfm}
{输入和判断应该是两个公用方法,传统遍历和递归都是一样的。}
procedure OutputData(AStrs : TStrings; AQueen : array of Integer; AStyleCount : Integer);
var
ASize : Integer; //数组长度
ALine : string; //记录一行字串
i , j : Integer; //循环变量
begin
//AStrs.Clear;
AStrs.Append('==StyleNo:'+inttostr(AStyleCount)+'==');
ASize := High(AQueen)-Low(AQueen)+1;
for i := Low(AQueen) to High(AQueen) do
begin
ALine := DupeString('☆',AQueen[i]) + '★'+ DupeString('☆',ASize-Aqueen[i]-1);
AStrs.Append(ALine);
end;
AStrs.Append('==========');
end;
//判断新皇后位置是否成立,其判断的位置坐标X,Y
function JudgeQueen(AQueen : array of Integer; APositionY, APositionX : Integer) : Boolean;
var
x , y : Integer; // x,y对应其临时比较值的横,纵坐标
begin
Result := False;
if APositionY>High(AQueen) then
Exit;
for y := 0 to APositionY-1 do
begin
x := AQueen[y];
if x=APositionX then //比较竖直线
Exit;
if x+y=APositionX+APositionY then //比较左上到右下的斜线
Exit;
if x-y=APositionX-APositionY then //比较右上到左下的斜线
Exit;
end;
Result := True;
end;
{ TfmQueen8 }
procedure TfmQueen8.btnRecurrenceClick(Sender: TObject);
var
i,StyleCount : Integer;
Queen : array of Integer; //皇后数据
QueenSize : Integer; //皇后数目
TimeTemp : TDateTime;
//进行皇后的递归计算
procedure Calc(AQueen : array of Integer; AIndex : Integer; var AStyleCount : Integer); //AIndex意义是,已成功检查完几阶
var
i : Integer;
begin
for i := Low(AQueen) to High(AQueen) do
begin
if JudgeQueen(AQueen,AIndex,i) then
begin
AQueen[AIndex] := i;
if AIndex=High(AQueen)-Low(AQueen) then
begin
Inc(AStyleCount);
OutputData(mem1.Lines,AQueen,AStyleCount);
//AQueen[AIndex] :=0;
//Sleep(1000);
Break;
end
else
Calc(AQueen,AIndex+1,StyleCount);
//AQueen[AIndex] :=i;
end;
end;
end;
begin
StyleCount :=0;
QueenSize :=spn1.Value;
SetLength(Queen,QueenSize);
for i := Low(Queen) to High(Queen) do
begin
Queen[i] := 0;
end;
TimeTemp := Now;
Calc(Queen,0,StyleCount);
mem1.Lines.Append(#13+'总共耗时'+inttostr(MilliSecondsBetween(TimeTemp,Now))+'毫秒');
end;
procedure TfmQueen8.btnGoThroughClick(Sender: TObject);
var
i,StyleCount : Integer;
Queen : array of Integer; //皇后数据
QueenSize : Integer; //皇后数目
TimeTemp : TDateTime;
//进行皇后的遍历计算
procedure Calc(AQueen : array of Integer; var AStyleCount : Integer);
var
i, Index : Integer; //Index意义是,当前变动的阶数
begin
Index := 0; //从第一个数开始检查起,这个跟递归初始化的参数一样。
while Index>=0 do //循环比较特殊,这里不能用For循环,因为循环的控制很复杂。
begin
Inc(AQueen[Index]); //先赋值,再对已赋值的数据进行判断。
while (AQueen[Index]<=High(AQueen)-Low(AQueen)) and not (JudgeQueen(AQueen,Index,AQueen[Index])) do
Inc(AQueen[Index]); //当前数据检查不通过时,直接转到当前行的下一列。
if (AQueen[Index]<=High(AQueen)-Low(AQueen)) and (Index=High(AQueen)-Low(AQueen)) then
begin //当数据检查通过,而Index满阶的时候,就直接输出。
Inc(AStyleCount);
OutputData(mem2.Lines,AQueen,AStyleCount);
end
else if (AQueen[Index]<=High(AQueen)-Low(AQueen)) and (Index<High(AQueen)-Low(AQueen)) then
begin
Inc(Index); //不满阶的时候,直接转下一行。
end
else //最后这种情况,其实是AQueen[Index]已经超出边界了,
begin //也就是这行根本没有合适位置,那么就跳转上一行,并且让上一行列增加
AQueen[Index]:=-1;
Dec(Index); //这里只需要调整行,列调整在下次循环首句处理。
end;
end;
end;
begin
StyleCount :=0;
QueenSize :=spn1.Value;
SetLength(Queen,QueenSize);
for i := Low(Queen) to High(Queen) do
begin
Queen[i] := -1;
end;
TimeTemp := Now;
Calc(Queen,StyleCount);
mem2.Lines.Append(#13+'总共耗时'+inttostr(MilliSecondsBetween(TimeTemp,Now))+'毫秒');
end;
procedure TfmQueen8.OutputStyle(AStrs: TStrings; AQueen: array of Integer);
var
QSize : Integer;
i,j : Integer;
ALine : string;
begin
QSize := High(AQueen)-Low(AQueen);
//未完成,这里想定义输出的各种符号风格来的。
end;
end.
//窗体代码文件uQueen8.dfm
object fmQueen8: TfmQueen8
Left = 0
Top = 0
Caption = 'Queen8'
ClientHeight = 388
ClientWidth = 528
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object lbl1: TLabel
Left = 8
Top = 8
Width = 48
Height = 13
Caption = #30343#21518#25968#30446
end
object spn1: TSpinEdit
Left = 62
Top = 6
Width = 121
Height = 22
MaxValue = 0
MinValue = 0
TabOrder = 0
Value = 8
end
object btnRecurrence: TBitBtn
Left = 32
Top = 44
Width = 137
Height = 25
Caption = #39640#25928#36882#24402#22238#26388#27861#35745#31639
DoubleBuffered = True
ParentDoubleBuffered = False
TabOrder = 1
OnClick = btnRecurrenceClick
end
object pnl1: TPanel
Left = 0
Top = 88
Width = 528
Height = 300
Align = alBottom
TabOrder = 2
object mem1: TMemo
Left = 1
Top = 1
Width = 255
Height = 298
Align = alClient
TabOrder = 0
end
object mem2: TMemo
Left = 256
Top = 1
Width = 271
Height = 298
Align = alRight
TabOrder = 1
end
end
object btnGoThrough: TBitBtn
Left = 280
Top = 44
Width = 169
Height = 25
Caption = #20256#32479#36941#21382#22238#26388#27861#35745#31639
DoubleBuffered = True
ParentDoubleBuffered = False
TabOrder = 3
OnClick = btnGoThroughClick
end
end