问题
There is a m*n Matrix
.
From one point of the matrix, you can move to one of the eight adjacent points (up, down, left, right, upper left, lower left, upper right, lower right
)
If the point in one direction has been visited, you can continue to move to the next unvisited point in this direction.
You cann't visit a point which has been visited, but you can pass through the visited adjacent point to visit other un-visited point.
For example, the current point is (5,5):
- If (5,4) has been visted, you can move to (5,3). If (5,3) is also visited, you can move the (5,2).
- The same as the diagonal direction. If (4,4) has been visited, you can be move to(3,3) and so on.
Now you need to visit all the points on the matrix, how many ways there are?
(The first and last point can be any point).
回答1:
This is similar to the number of Greek-key tours on a board / AKA number of self-avoiding walks (see Wikipedia) on a grid.
But in your variation, you can move to 8 directions, instead of 4.
For the original version, It seems that there is no known formula for large values of n. It is explained here and here.
I implemented a short C++ program to count it for your case (not the most efficient one, I guess):
const size_t _DIM_m= 4; // cols
const size_t _DIM_n= 4; // rows
typedef struct // we want to pass the array by value (for recursion), so we'll wrap it with a struct
{
bool g[_DIM_m][_DIM_n];
} Grid;
int Traverse(Grid g, int i, int j, int nVisit= 0)
{
int nWays= 0;
++nVisit; // points visited so far
g.g[i][j]= true;
Grid h= g;
// original problem:
if ( (0 != j) && (!g.g[i ][j-1])) nWays+= Traverse(g, i , j-1, nVisit); // up
if ( (_DIM_n-1 != j) && (!g.g[i ][j+1])) nWays+= Traverse(g, i , j+1, nVisit); // down
if ((0 != i) && (!g.g[i-1][j ])) nWays+= Traverse(g, i-1, j , nVisit); // left
if ((_DIM_m-1 != i) && (!g.g[i+1][j ])) nWays+= Traverse(g, i+1, j , nVisit); // right
// additions for your problem:
if ((_DIM_m-1 != i) && (0 != j) && (!g.g[i+1][j-1])) nWays+= Traverse(g, i+1, j-1, nVisit); // upper right
if ((0 != i) && (_DIM_n-1 != j) && (!g.g[i-1][j+1])) nWays+= Traverse(g, i-1, j+1, nVisit); // lower left
if ((0 != i) && (0 != j) && (!g.g[i-1][j-1])) nWays+= Traverse(g, i-1, j-1, nVisit); // upper left
if ((_DIM_m-1 != i) && (_DIM_n-1 != j) && (!g.g[i+1][j+1])) nWays+= Traverse(g, i+1, j+1, nVisit); // lower right
if (_DIM_m * _DIM_n == nVisit) ++nWays; // if all points visited
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); // starting point: 0, 0
cout << nWays << endl;
system ("pause");
return 0;
}
The results for a rectangular grid, starting from (0,0):
- _DIM= 1: 1
- _DIM= 2: 6
- _DIM= 3: 138
- _DIM= 4: 37948
- _DIM= 5: a lot...
Note that the results changes when starting from a different point.
Edit:
Original question was modified: pass-through was added. Here is a solution for this case:
const size_t _DIM_m= 4; // cols
const size_t _DIM_n= 4; // rows
typedef struct // we want to pass the array by value (for recursion), so we'll wrap it with a 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; // points visited so far
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])); // up (pass through)
if (InRange(i1,j1)) nWays+= Traverse(g, i1, j1, nVisit);
i1= i; j1= j;
do { ++j1; } while (InRange(i1,j1) && (g.g[i1][j1])); // down (pass through)
if (InRange(i1,j1)) nWays+= Traverse(g, i1, j1, nVisit);
i1= i; j1= j;
do { --i1; } while (InRange(i1,j1) && (g.g[i1][j1])); // left (pass through)
if (InRange(i1,j1)) nWays+= Traverse(g, i1, j1, nVisit);
i1= i; j1= j;
do { ++i1; } while (InRange(i1,j1) && (g.g[i1][j1])); // right (pass through)
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])); // upper right (pass through)
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])); // lower left (pass through)
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])); // upper left (pass through)
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])); // lower right (pass through)
if (InRange(i1,j1)) nWays+= Traverse(g, i1, j1, nVisit);
if (_DIM_m * _DIM_n == nVisit) ++nWays; // if all points visited
return nWays;
}
The results for a rectangular grid, starting from (0,0):
- _DIM= 1: 1
- _DIM= 2: 6
- _DIM= 3: 1020
- _DIM= 4: 8071182
- _DIM= 5: a lot...
回答2:
Sounds like a typical TSP problem (see: http://en.wikipedia.org/wiki/Travelling_salesman_problem ). Each box e.g. 5,5 is like a city and there are only 'roads' or links which can reach another node or 'city'. Hope that helps ya
来源:https://stackoverflow.com/questions/13410168/how-many-ways-to-visit-all-the-points-of-a-given-matrix