“邻居函数”优化使用A * -Algorithm解决8-Puzzle

时间:2016-06-21 18:12:37

标签: c# c++ c algorithm delphi

我找到了A*-Algorithm 我想用它来找到8-Puzzle的最佳解决方案。

就像图片中的拼图一样:

0 1 2
3 4 5
6 7 8

并表示为数组:0 1 2 3 4 5 6 7 8

“Neighbor-function”返回数组索引的所有邻居。 邻居是距离数组索引垂直或水平一个字段的所有数字。

示例:邻居(4)将返回1,5,7,3而邻居(6)将返回3,7

我目前的解决方案(由Uwe Raabe编码):

function Neighbours(zahl: Integer): TArray<Integer>;
var
  lst: TList<Integer>;
  c: Integer;
  r: Integer;
begin
  lst := TList<Integer>.Create;
  try
    c := zahl mod 3;
    r := zahl div 3;
    if r > 0 then
      lst.Add(zahl-3);
    if c > 0 then
      lst.Add(zahl-1);
    if c < 2 then
      lst.Add(zahl+1);
    if r < 2 then
      lst.Add(zahl+3);
    result := lst.ToArray;
  finally
    lst.Free;
  end;
end;

我正在寻找一种紧凑而且更好的解决方案。我很想看到一些算法。我不喜欢if等。编程语言并不重要,只要它可以移植到其中一个:C / C ++ / Delphi / C#

提前致谢!

4 个答案:

答案 0 :(得分:2)

正如评论中所提到的,您只需要一个查找表。邻居的数量不是恒定的,因此您需要一种方法来了解每个方块有多少邻居。这可以使用sentinel value完成,如下所示

int neighbors[9][5] = {
    {  1, 3,-1,-1,-1 },
    {  0, 2, 4,-1,-1 },
    // etc
};

int main( void )
{
    // get the list of neighbors for square 1
    int *list = neighbors[1];

    // print the list of neighbors
    for ( int i = 0; list[i] >= 0; i++ )
        printf( "%d\n", list[i] );
}

请注意,查找表可以手动编码,也可以在启动时通过您已有的代码自动生成。

答案 1 :(得分:1)

使用Delphi XE7或更新的查找表解决方案是紧凑的:

function Neighbours( number: Integer): TArray<Integer>;
const
  resCount: array[0..8] of Integer = (2,3,2,3,4,3,2,3,2);
  resValue: TArray<TArray<Integer>> = [
    [1,3,-1,-1],
    [0,2,4,-1],
    [1,5,-1,-1],
    [0,4,6,-1],
    [1,3,5,7],
    [2,4,8,-1],
    [3,7,-1,-1],
    [4,6,8,-1],
    [5,7,-1,-1]];
begin
  SetLength(Result,4);  // Set default length
  Result := resValue[number];  // Assign a solution vector
  SetLength(Result,resCount[number]); // Correct result length
end;

您不太可能找到比您问题中给出的算法更紧凑的算法。即使您认为if语句难看,它们也是有效的,并且是每种(几乎)编程语言的核心部分。

或者使用OP提议的集合:

Type
  TMySet = set of 0..8;

function Neighbours( number: Integer): TMySet;
const 
  NeighboursA: array[0..8] of TMySet = 
    ([1,3], [0,2,4], [1,5], [0,4,6],[1,3,5,7], [2,4,8], [3,7], [4,6,8], [5,7]);
begin
  Result := NeighboursA[number];
end;

答案 2 :(得分:1)

这些回复主要关注矩阵的静态x和y大小...如果你对algorythmics感兴趣,你可以将它们变为变量:

function Neighbours(zahl: Integer; xSize,Ysize:integer): TArray<Integer>;
var
  lst: TList<Integer>;
  x: Integer;
  y: Integer;
begin
  lst := TList<Integer>.Create;
  try
    x := zahl mod xSize;
    y := zahl div ySize;
    if x > 0 then
      lst.Add(zahl-1);
    if x < (xSize - 1) then
      lst.Add(zahl+1);
    if y > 0 then
      lst.Add(zahl-xSize);
    if y < (ySize - 1) then
      lst.Add(zahl+xSize);
    result := lst.ToArray;
  finally
    lst.Free;
  end;
end;

答案 3 :(得分:0)

我有一个拼写网格的求解器,它可以通过algorythm在c#中执行此操作,该算法适用于任何大小的矩阵

private void InitPaths()
{
    PathDictionary.Clear();

    for (var rowstart = 0; rowstart < GridRowSize; rowstart++)
    {
        for (var colstart = 0; colstart < GridColSize; colstart++)
        {
            var tuples = new List<Tuple<int, int>>();

            for (var r = rowstart - 1; r <= rowstart + 1; r++)
            {
                if (r < 0 || r >= GridRowSize) continue;

                for (var c = colstart - 1; c <= colstart + 1; c++)
                {
                    if (c < 0 || c >= GridColSize || (r == rowstart && c == colstart)) continue;

                    tuples.Add(new Tuple<int, int>(r, c));
                }
            }

            PathDictionary.Add(new Tuple<int, int>(rowstart, colstart), tuples);
        }
    }
}