八皇后回溯计算法研究

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

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

多遍历了很多东西。

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

时间: 2024-11-20 04:33:32

八皇后回溯计算法研究的相关文章

八皇后回溯递归 40行不到

个人感觉代码还算精简,比较容易混淆的一点是,board[] 数组,数组下表指的是八皇后棋盘的行,数组下标对应的值指的是八皇后棋盘的列,至于abs()可以去百度,是一个求绝对值的函数 #include <iostream> using namespace std ; #define N 8 static int sum = 0 ; const int max = N ; void print (int board []) { for(int i = 0 ;i < max ;i++) { c

八皇后92

#include <stdlib.h>   #include <stdio.h>       int m[8][8] = {0};//表示棋盘,初始为0,表示未放置皇后   int num = 0;//解数目     //对于棋盘前row-1行已放置好皇后   //检查在第row行.第column列放置一枚皇后是否可行    bool check(int row,int column)    {        if(row==1) return true;        int i

回溯算法解八皇后问题(java版)

八皇后问题是学习回溯算法时不得不提的一个问题,用回溯算法解决该问题逻辑比较简单. 下面用java版的回溯算法来解决八皇后问题. 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法. 思路是按行来规定皇后,第一行放第一个皇后,第二行放第二个,然后通过遍历所有列,来判断下一个皇后能否放在该列.直到所有皇后都放完,或者放哪

【八皇后问题】 回溯算法

回溯算法:回溯算法实际上是一个类似枚举的搜索尝试方法,它的思想是在搜索尝试中寻找问题的解,当发现不满足求解条件时,就“回溯”返回,尝试别的路径.之前介绍的基础算法中的贪婪算法,动态规划等都具有“无后效性”,也就是在分段处理问题时,某状态一旦确定,将不再改变.而多数问题很难找到"无后效性”的阶段划分和相应决策,而是通过深入搜索尝试和回溯操作完成的. 八皇后问题:8*8的国际象棋棋盘中放八个皇后,是任意两个皇后不能互相吃掉.规则:皇后能吃掉同一行,同一列,同一对角线的任意棋子. 模型建立:不妨设八个

2、八皇后问题——回溯法

/** * */ package unit1; /** * @author * @version 创建时间:2015-10-30 下午02:55:24 类说明 */ public class EightQueensNotRecursive { private static final boolean AVAILABLE = true; private int squares = 16, norm = squares - 1; private int positionInRow[] = new i

八皇后问题(回溯法&amp;枚举法)

作者 : 卿笃军 本文讨论了八皇后问题的三种解决方案: 一.枚举法 二.回溯法(递归版) 三.回溯法(非递归版) 本来这些代码是以前编写好的,没有发表,由于最近又学习到了八皇后问题,自己整理了一下发表了出来! 首先.说明一下何为八皇后问题,我也不去谷歌了,直接简单的说明一下: 八皇后问题,就是在一个8*8的平面棋盘上,要求你摆放8个棋子,要求:这8个棋子不能有2个在同一行,也不能有2个在同一列,同时一条斜线上面也不能有2个~~~~ 比如:4*4的棋盘,你可以这样摆放(4皇后问题): 以上图为参照

八皇后問題 (C語言递归實現 回溯法)

八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行.纵行或斜线上.現在要統計出所有的可行方案的總數,而且輸出每一種方案皇后擺放的坐標: 代碼詳細解析: #include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <cstd

【Python】生成器、回溯和八皇后问题

八皇后问题: 把N个皇后,放在N*N的棋盘上面,从第一行往下放,每个皇后占一行,同时,每个皇后不能处在同一列,对角线上,有多少种放置方法. 思路: 典型的回溯问题: 1.当要放置最后一个皇后时候,默认前N-1个皇后已经全部放置好了,那么验证在第N行上的每个位置是否可行,即是否与之前的皇后在同一列或者对角线即可: 2.如果放置的不是最后一个皇后,则回溯.回溯至刚开始放第一个元素时候,然后不断的返回上一层.每一层都认为下一层传递给自己的是正确的信息 1 def isconflict(state, n

八皇后问题-回溯法(matlab)

1.问题描述 八皇后问题是十九世纪著名数学家高斯于1850年提出的.问题是:在8*8的棋盘上摆放8个皇后,使其不能互相攻击,即任意的两个皇后不能处在同意行,同一列,或同意斜线上. 2.matlab代码 function PlaceQueen(row,stack,N)%回溯法放置皇后 if row>N PrintQueen(N,stack);%打印棋盘 else for col=1:N stack(row)=col; if row==1||Conflict(row,col,N,stack)%检测是