I've made a working algorithm for finding a Hamiltonian cycle in a grid graph. However, the approach I implemented includes recursively checking all the possible combinations until I find the right one. This is fine on small graphs (like 6*6), but becomes way too slow on bigger ones, the ones that I need to find the cycle for (30 * 30).
In main I initialize a 2D vector of ints, representing out graph (board
), and initalize it to -1. -1 represents that this space hasn't been 'filled' yet, while values above that represent their place in the cycle (0 - first cell, 1 - second cell etc.). And I use initialize a Vector2f (SFML's way of doing vectors, same as pairs in standard library), which I use to step all the possible states.
And I also initialize the path integer, which will help up later.And lastly I call the Hamiltionan cycle finding algorithm (HamCycle()
).
int main(){
int path = 0;
int bx = 8;
std::vector<std::vector<int>> board{ 8 };
Vector2f pos = { 4 , 4 };
for (int i = 0; i < bx; i++) {
board[i].resize(bx);
for (int j = 0; j < bx; j++) board[i][j] = -1;
}
hamCycle(board, pos, path, bx);
};
Then I hamCycle()
I check if pos
vector goes outside of the grid, and if so return false. Else I give this cell the value of path, which is then increased. I check if the algorithm is done, and if it's a cycle or just a path. If it's a path, it returns false. Then I recursively check the cells around it and repeat the process.
bool hamCycle(std::vector<std::vector<int>> &board,Vector2f pos, int &path, int bx) {
//check if it's outside the box and if it's already occupied
if (pos.x >= bx || pos.x < 0 || pos.y >= bx || pos.y < 0) return false;
if (board[pos.x][pos.y] != -1) return false;
board[pos.x][pos.y] = path;
path++;
//check if the cycle is completed
bool isDone = true;
if (path != (bx * bx)) isDone = false;
//check if this cell is adjacent to the beggining and if so it's done
if (isDone) {
if (pos.x != 0 && pos.x != (size - 1) && pos.y != 0 && pos.y != (size - 1)) {
if ((board[pos.x + 1][pos.y] == 0) || (board[pos.x - 1][pos.y] == 0) || (board[pos.x][pos.y
+ 1] == 0)
|| (board[pos.x][pos.y - 1] == 0)) {
return true;
}
path--;
board[pos.x][pos.y] = -1;
return false;
}
else {
path--;
board[pos.x][pos.y] = -1;
return false;
};
}
//recursion time
if (hamCycle(board, Vector2f(pos.x + 1, pos.y), path, bx)) return true;
if (hamCycle(board, Vector2f(pos.x - 1, pos.y), path, bx)) return true;
if (hamCycle(board, Vector2f(pos.x, pos.y + 1), path, bx)) return true;
if (hamCycle(board, Vector2f(pos.x, pos.y - 1), path, bx)) return true;
path--;
board[pos.x][pos.y] = -1;
return false;
}
Right now it spends a lot of time checking all possible paths when it has already blocked an exit, which is innefficent. How can I improve this, so checking big grids is feasible? Like not checking if has a blocked exit, but if you know any other methods for improvement, please let me know.