通过网格的最大路径数的公式?

时间:2010-01-03 22:06:55

标签: grid graph puzzle

给定一个开放点的网格,以及放置在这些点中的一定数量的图块,f(openSpots, tilesToPlace)函数将为您提供可以形成的连续路径的数量?

连续路径是切片的放置,使得每个切片与另一个切片共享边缘。 (只有角落触摸不够好。(0, 1)(0, 0)是合法的,但(1, 1)(2, 2)不合法。)

我已经有了一个可以找到所有这些路径的函数。但是,它仅适用于少数。对于较大的值,我需要的只是可能存在的数量的计数。以下是一些数据:

For 1 tiles, there are 1 paths.
For 2 tiles, there are 4 paths.
For 3 tiles, there are 22 paths.
For 4 tiles, there are 89 paths.
For 5 tiles, there are 390 paths.
For 6 tiles, there are 1476 paths.
For 7 tiles, there are 5616 paths.
For 8 tiles, there are 19734 paths.
For 9 tiles, there are 69555 paths.

随着拼图大小的增加,计算得非常慢。我认为我的寻路解决方案的渐近复杂性非常糟糕。

如果有n个图块,则网格的长度和宽度最多为n个。

1 个答案:

答案 0 :(得分:1)

您的问题似乎至少与enumerating polyominoes一样困难。没有已知的快速算法可以做到这一点,并且在n = 50之后,最着名的算法很难。我怀疑有一种解决这个问题的快捷方法。

我甚至不会假装这是一个最佳解决方案,但它可能有用作参考解决方案。我认为它至少给出了正确答案,尽管需要一些时间。它通过查找长度为n-1的所有路径递归地解决问题,然后检查所有可能的位置,它可以添加一个更多的磁贴并删除重复的解决方案。它有一个特别难看的部分,它通过将路径转换为字符串并比较字符串来检查重复,但写入速度很快。

这是它生成的输出:

n = 1, number of paths found = 1
n = 2, number of paths found = 4
n = 3, number of paths found = 22
n = 4, number of paths found = 113
n = 5, number of paths found = 571
n = 6, number of paths found = 2816
n = 7, number of paths found = 13616
n = 8, number of paths found = 64678
n = 9, number of paths found = 302574

这是代码:

using System;
using System.Collections.Generic;
using System.Linq;

public struct Tile
{
    public Tile(int x, int y) { X = x; Y = y; }
    public readonly int X;
    public readonly int Y;
    public IEnumerable<Tile> GetNeighbours(int gridSize)
    {
        if (X > 0)
            yield return new Tile(X - 1, Y);
        if (X < gridSize - 1)
            yield return new Tile(X + 1, Y);
        if (Y > 0)
            yield return new Tile(X, Y - 1);
        if (Y < gridSize - 1)
            yield return new Tile(X, Y + 1);
    }
    public override string ToString()
    {
        return string.Format("({0},{1})", X, Y);
    }
}

public class Path
{
    public Path(Tile[] tiles) { Tiles = tiles; }
    public Tile[] Tiles { get; private set; }
    public override string ToString()
    {
        return string.Join("", Tiles.Select(tile => tile.ToString()).ToArray());
    }
}

public class PathFinder
{
    public IEnumerable<Path> FindPaths(int n, int gridSize)
    {
        if (n == 1)
        {
            for (int x = 0; x < gridSize; ++x)
                for (int y = 0; y < gridSize; ++y)
                    yield return new Path(new Tile[] { new Tile(x, y) });
        }
        else
        {
            Dictionary<string, object> pathsSeen = new Dictionary<string, object>();
            foreach (Path shortPath in FindPaths(n - 1, gridSize))
            {
                foreach (Tile tile in shortPath.Tiles)
                {
                    foreach (Tile neighbour in tile.GetNeighbours(gridSize))
                    {
                        // Ignore tiles that are already included in the path.
                        if (shortPath.Tiles.Contains(neighbour))
                            continue;

                        Path newPath = new Path(shortPath.Tiles
                            .Concat(new Tile[] { neighbour })
                            .OrderBy(t => t.X)
                            .ThenBy(t => t.Y)
                            .ToArray());

                        string pathKey = newPath.ToString();
                        if (!pathsSeen.ContainsKey(pathKey))
                        {
                            pathsSeen[pathKey] = null;
                            yield return newPath;
                        }
                    }
                }
            }
        }
    }

    static void Main()
    {
        PathFinder pathFinder = new PathFinder();
        for (int n = 1; n <= 9; ++n)
        {
            List<Path> paths = pathFinder.FindPaths(n, n).ToList();
            Console.WriteLine("n = {0}, number of paths found = {1}", n, paths.Count);
            //foreach (Path path in paths)
            //    Console.WriteLine(path.ToString());
        }
    }
}