罗密欧与朱丽叶身处一个 m × n 的迷宫中,如下图所示。每一个方格表示迷宫中的一个房间。这 m × n 个房间中有一些房间是封闭的,不允许任何人进入。在迷宫中任何位置均可沿 8 个方向进入未封闭的房间。罗密欧位于迷宫的 (p , q) 方格中,他必须找出一条通向朱丽叶所在的 (r , s) 方格的路。在抵达朱丽叶之前,他必须走遍所有未封闭的房间各一次,而且要使到达朱丽叶的转弯次数为最少。每改变一次前进方向算作转弯一次。请设计一个算法帮助罗密欧找出这样一条道路。【分支限界法】
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#include <climits>
using namespace std;
// 8个移动方向
int dir[8][2] = {{-1,-1},{-1,0},{-1,1},
{0,-1}, {0,1},
{1,-1}, {1,0},{1,1}};
const int MAXN = 8;
int n, m; // n行m列
int grid[MAXN][MAXN]; // 1封锁,0可走
int sx, sy, ex, ey; // 起点(sx,sy) 终点(ex,ey)
int total = 0; // 需要走完的空房间总数
int vis_record[MAXN][MAXN][8][1<<25]; // 状态剪枝:xy+来向+访问掩码
struct Node {
int x, y;
int pre_dir; // 上一步方向 -1起点
int turn; // 转弯次数
int mask; // 位图记录走过的格子
// 优先队列:转弯小优先
bool operator>(const Node& other) const {
return turn > other.turn;
}
};
// 坐标转编号:扁平化格子下标
inline int getid(int x,int y) {
return x*m + y;
}
int bfs() {
priority_queue<Node, vector<Node>, greater<Node>> q;
memset(vis_record, 0x3f, sizeof(vis_record));
Node st;
st.x = sx; st.y = sy;
st.pre_dir = -1;
st.turn = 0;
int id = getid(sx,sy);
st.mask = 1 << id;
q.push(st);
vis_record[sx][sy][0][st.mask] = 0;
while (!q.empty()) {
auto cur = q.top();
q.pop();
// 全部走完且抵达终点,返回答案
if (__builtin_popcount(cur.mask) == total && cur.x == ex && cur.y == ey) {
return cur.turn;
}
for (int d = 0; d < 8; d++) {
int nx = cur.x + dir[d][0];
int ny = cur.y + dir[d][1];
if(nx<0||nx>=n||ny<0||ny>=m) continue;
if(grid[nx][ny]==1) continue; // 封闭格子不能走
int nid = getid(nx,ny);
if((cur.mask & (1<<nid)) !=0) continue; // 已经走过
Node nex = cur;
nex.x = nx; nex.y = ny;
nex.mask |= (1<<nid);
// 计算转弯
if(cur.pre_dir == -1) {
nex.turn = cur.turn;
} else if(d != cur.pre_dir) {
nex.turn = cur.turn + 1;
} else {
nex.turn = cur.turn;
}
nex.pre_dir = d;
// 状态剪枝:同位置同方向同掩码,已有更优解则不入队
if(nex.turn < vis_record[nx][ny][d][nex.mask]) {
vis_record[nx][ny][d][nex.mask] = nex.turn;
q.push(nex);
}
}
}
return -1; // 无解
}
int main() {
cin >> n >> m;
total = 0;
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
cin >> grid[i][j];
if(grid[i][j]==0) total++;
}
}
cin >> sx >> sy >> ex >> ey;
cout << bfs() << endl;
return 0;
}