给定一个开放点的网格,以及放置在这些点中的一定数量的图块,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
个。
答案 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());
}
}
}