八皇后回溯计算法研究

Posted 莫霏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了八皇后回溯计算法研究相关的知识,希望对你有一定的参考价值。

仔细看了下百度中的回溯法介绍,这是一种非常有用的算法,大概有两种模式,一种是遍历,一种是递归。

我把这两种方法都列出来了,按网上的说法,递归效率要比遍历快很多,我这里测试是一样的,可能是网络上那些遍历法根本没优化好吧,

多遍历了很多东西。

网上并没有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

以上是关于八皇后回溯计算法研究的主要内容,如果未能解决你的问题,请参考以下文章

回溯法解决八皇后问题

求教C语言回溯法写出八皇后问题的92种解

每天刷个算法题20160519:回溯法解八皇后

八皇后问题算法详解

暴力回溯法 解八皇后

回溯法求解八皇后问题---(初步未优化)