这与棋盘上的希腊钥匙旅行数量 / 即网格上的自避行走数量(
参见维基百科)相似。
但在您的变体中,您可以向8个方向移动,而不是4个。
对于原始版本,似乎没有已知的公式适用于大量的n。 这里和这里有解释。
我编写了一个简短的C++程序来计算您的情况(我猜不是最有效的):
const size_t _DIM_m= 4;
const size_t _DIM_n= 4;
typedef struct
{
bool g[_DIM_m][_DIM_n];
} Grid;
int Traverse(Grid g, int i, int j, int nVisit= 0)
{
int nWays= 0;
++nVisit;
g.g[i][j]= true;
Grid h= g;
if ( (0 != j) && (!g.g[i ][j-1])) nWays+= Traverse(g, i , j-1, nVisit);
if ( (_DIM_n-1 != j) && (!g.g[i ][j+1])) nWays+= Traverse(g, i , j+1, nVisit);
if ((0 != i) && (!g.g[i-1][j ])) nWays+= Traverse(g, i-1, j , nVisit);
if ((_DIM_m-1 != i) && (!g.g[i+1][j ])) nWays+= Traverse(g, i+1, j , nVisit);
if ((_DIM_m-1 != i) && (0 != j) && (!g.g[i+1][j-1])) nWays+= Traverse(g, i+1, j-1, nVisit);
if ((0 != i) && (_DIM_n-1 != j) && (!g.g[i-1][j+1])) nWays+= Traverse(g, i-1, j+1, nVisit);
if ((0 != i) && (0 != j) && (!g.g[i-1][j-1])) nWays+= Traverse(g, i-1, j-1, nVisit);
if ((_DIM_m-1 != i) && (_DIM_n-1 != j) && (!g.g[i+1][j+1])) nWays+= Traverse(g, i+1, j+1, nVisit);
if (_DIM_m * _DIM_n == nVisit) ++nWays;
return nWays;
}
int _tmain(int argc, _TCHAR* argv[])
{
Grid g;
for (size_t i= 0; i<_DIM_m; i++)
for (size_t j= 0; j<_DIM_n; j++)
g.g[i][j]= false;
int nWays= Traverse(g, 0, 0);
cout << nWays << endl;
system ("pause");
return 0;
}
矩形网格的结果,从 (0,0) 开始:
- _DIM= 1: 1
- _DIM= 2: 6
- _DIM= 3: 138
- _DIM= 4: 37948
- _DIM= 5: 很多...
请注意,从不同的起点开始时,结果会发生变化。
编辑:
原问题已被修改:添加了 pass-through。以下是此情况的解决方案:
const size_t _DIM_m= 4;
const size_t _DIM_n= 4;
typedef struct
{
bool g[_DIM_m][_DIM_n];
} Grid;
inline bool InRange(int i, int j)
{
return (i >= 0) && (i < _DIM_m) && (j >= 0) && (j < _DIM_n);
}
int Traverse(Grid g, int i, int j, int nVisit= 0)
{
int nWays= 0;
++nVisit;
g.g[i][j]= true;
Grid h= g;
int i1,j1;
i1= i; j1= j;
do { --j1; } while (InRange(i1,j1) && (g.g[i1][j1]));
if (InRange(i1,j1)) nWays+= Traverse(g, i1, j1, nVisit);
i1= i; j1= j;
do { ++j1; } while (InRange(i1,j1) && (g.g[i1][j1]));
if (InRange(i1,j1)) nWays+= Traverse(g, i1, j1, nVisit);
i1= i; j1= j;
do { --i1; } while (InRange(i1,j1) && (g.g[i1][j1]));
if (InRange(i1,j1)) nWays+= Traverse(g, i1, j1, nVisit);
i1= i; j1= j;
do { ++i1; } while (InRange(i1,j1) && (g.g[i1][j1]));
if (InRange(i1,j1)) nWays+= Traverse(g, i1, j1, nVisit);
i1= i; j1= j;
do { ++i1; --j1; } while (InRange(i1,j1) && (g.g[i1][j1]));
if (InRange(i1,j1)) nWays+= Traverse(g, i1, j1, nVisit);
i1= i; j1= j;
do { --i1; ++j1; } while (InRange(i1,j1) && (g.g[i1][j1]));
if (InRange(i1,j1)) nWays+= Traverse(g, i1, j1, nVisit);
i1= i; j1= j;
do { --i1; --j1; } while (InRange(i1,j1) && (g.g[i1][j1]));
if (InRange(i1,j1)) nWays+= Traverse(g, i1, j1, nVisit);
i1= i; j1= j;
do { ++i1; ++j1; } while (InRange(i1,j1) && (g.g[i1][j1]));
if (InRange(i1,j1)) nWays+= Traverse(g, i1, j1, nVisit);
if (_DIM_m * _DIM_n == nVisit) ++nWays;
return nWays;
}
一个从(0,0)开始的矩形网格的结果如下:
- _DIM= 1: 1
- _DIM= 2: 6
- _DIM= 3: 1020
- _DIM= 4: 8071182
- _DIM= 5: 很多...
2^(n-1)
种组合。现在如果你再加上第二行,事情就变得非常复杂了(至少对我而言是这样)。我猜测答案应该是2^(n*m-1)
,但是没有证明。 - VesperA
经过,以访问与A
方向相同的相邻点。 - fanjindou