题意:
给你一个N * M(1 ≤ N, M ≤ 20)的地图,'.'表示空位,'*'表示垃圾,'o'表示机器人的初始位置,'x'表示墙。请你计算机器人清理完所有的垃圾至少要走多少步。
机器人一旦走到垃圾上,垃圾就被清掉了。输入数据保证垃圾不多于10个。
思路:
1. 先 BFS 求出任意两个污点间所需要的最小步数。题目保证了污点数不超过 10 个,这时候可以应用经典的 TSP 模型,用状态压缩 dp 解决之;
2. dp[u][s] 代表以 u 结束的状态 s 需要经过的最小步数。 s 中的位代表已经选择了的污点,初始状态 dp[0][0] = 0, 其他赋值 INFS,求解 dp[i][ends] 最小值。
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int INFS = 0x3fffffff;
const int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
char grid[25][25];
int col, row, dis[15][15];
bool vis[25][25];
struct Dirty {
int x, y;
} dirty[20] ;
struct ST {
int x, y, step, f;
ST(int _x, int _y, int _step, int _f) : x(_x), y(_y), step(_step), f(_f) {}
bool operator < (const ST& other) const {
return f > other.f;
}
};
bool judge(int x, int y) {
if (0 < x && x <= row && 0 < y && y <= col && grid[x][y] != 'x') {
return true;
}
return false;
}
int getdiff(const Dirty& a, const Dirty& b) {
return abs(a.x - b.x) + abs(a.y - b.y);
}
int bfs(const Dirty& src, const Dirty& dst) {
priority_queue<ST> Q;
Q.push(ST(src.x, src.y, 0, getdiff(src, dst)));
memset(vis, false, sizeof(vis));
vis[src.x][src.y] = true;
while (!Q.empty()) {
ST u = Q.top();
Q.pop();
if (u.x == dst.x && u.y == dst.y)
return u.step;
for (int i = 0; i < 4; i++) {
Dirty v;
v.x = u.x + dir[i][0];
v.y = u.y + dir[i][1];
if (judge(v.x, v.y) && !vis[v.x][v.y]) {
vis[v.x][v.y] = true;
int f = u.step + 1 + getdiff(v, dst);
Q.push(ST(v.x, v.y, u.step + 1, f));
}
}
}
return -1;
}
int dp[12][1<<12];
int dirtycnt;
inline int getflag(int r) {
return 1 << r;
}
int dfs(int state, int u) {
if (dp[u][state] != INFS)
return dp[u][state];
int s = state ^ getflag(u - 1);
if (s == 0)
return dis[0][u];
for (int i = 1; i <= dirtycnt; i++) {
if (s & getflag(i-1)) {
dp[u][state] = min(dp[u][state], dfs(s, i) + dis[i][u]);
}
}
return dp[u][state];
}
int main() {
while (scanf("%d%d", &col, &row) && col && row) {
memset(dirty, 0, sizeof(dirty));
dirtycnt = 0;
for (int i = 1; i <= row; i++) {
scanf("%s", &grid[i][1]);
for (int j = 1; j <= col; j++) {
if (grid[i][j] == '*') {
dirtycnt += 1;
dirty[dirtycnt].x = i;
dirty[dirtycnt].y = j;
} else if (grid[i][j] == 'o') {
dirty[0].x = i; dirty[0].y = j;
}
}
}
bool flag = false;
for (int i = 0; i <= dirtycnt; i++) {
for (int j = i; j <= dirtycnt; j++) {
if (i == j) {
dis[i][j] = 0;
} else {
dis[j][i] = dis[i][j] = bfs(dirty[i], dirty[j]);
if (dis[i][j] == -1) {
flag = true; break;
}
}
}
}
if (flag) {
printf("-1\n"); continue;
}
int ends = getflag(dirtycnt) - 1;
for (int i = 0; i <= dirtycnt; i++) {
for (int j = 0; j <= ends; j++)
dp[i][j] = INFS;
}
dp[0][0] = 0;
int ans = INFS;
for (int i = 1; i <= dirtycnt; i++)
ans = min(ans, dfs(ends, i));
printf("%d\n", ans);
}
return 0;
}