题意:求回收所有垃圾的最短路
思路:先BFS处理两个垃圾的距离,然后DFS记忆化搜索
dp[i][state]表示处理到第i个后状态是state的最短路
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int MAXN = 30;
const int INF = 0x3f3f3f3f;
struct Point {
int x,y;
}point[20];
struct node {
int x,y,step,f;
node(int _x, int _y, int _step, int _f) {
x = _x, y = _y, step = _step, f = _f;
}
bool operator< (const node a)const {
return f > a.f;
}
};
char map[MAXN][MAXN];
int n,m;
int dx[4] = {1,-1,0,0};
int dy[4] = {0,0,1,-1};
int dis[MAXN][MAXN], vis[MAXN][MAXN];
int dp[12][1<<12],sum;
int check(int x, int y) {
if (x > 0 && x <= n && y > 0 && y <= m && map[x][y] != 'x')
return 1;
return 0;
}
int getdiff(const Point &a, const Point &b) {
return abs(a.x-b.x) + abs(a.y-b.y);
}
int bfs(const Point &a, const Point &b) {
priority_queue<node > q;
q.push(node(a.x, a.y, 0, getdiff(a, b)));
memset(vis, 0, sizeof(vis));
vis[a.x][a.y] = 1;
while (!q.empty()) {
node cur = q.top();
q.pop();
if (cur.x == b.x && cur.y == b.y)
return cur.step;
for (int i = 0; i < 4; i++) {
Point tmp;
tmp.x = cur.x + dx[i];
tmp.y = cur.y + dy[i];
if (check(tmp.x, tmp.y) && !vis[tmp.x][tmp.y]) {
vis[tmp.x][tmp.y] = 1;
int f = cur.step+1+getdiff(tmp, b);
q.push(node(tmp.x, tmp.y, cur.step+1, f));
}
}
}
return -1;
}
int getFlag(int i) {
return 1<<i;
}
int dfs(int st, int u) {
if (dp[u][st] != INF)
return dp[u][st];
int s = st^getFlag(u-1);
if (s == 0)
return dis[0][u];
for (int i = 1; i <= sum; i++)
if (s & getFlag(i-1))
dp[u][st] = min(dp[u][st], dfs(s, i)+dis[i][u]);
return dp[u][st];
}
int main() {
while (scanf("%d%d", &m, &n) != EOF && n+m) {
memset(map, 0, sizeof(map));
sum = 0;
for (int i = 1; i <= n; i++) {
scanf("%s", &map[i][1]);
for (int j = 1; j <= m; j++)
if (map[i][j] == '*') {
++sum;
point[sum].x = i;
point[sum].y = j;
}
else if (map[i][j] == 'o') {
point[0].x = i;
point[0].y = j;
}
}
int flag = 0;
for (int i = 0; i <= sum; i++) {
for (int j = i; j <= sum; j++) {
if (i == j)
dis[i][j] = 0;
else {
dis[i][j] = dis[j][i] = bfs(point[i], point[j]);
if (dis[i][j] == -1) {
flag = 1;
break;
}
}
}
}
if (flag) {
printf("-1\n");
continue;
}
int ends = getFlag(sum) - 1;
for (int i = 0; i <= sum; i++)
for (int j = 0; j <= ends; j++)
dp[i][j] = INF;
dp[0][0] = 0;
int ans = INF;
for (int i = 1; i <= sum; i++)
ans = min(ans, dfs(ends, i));
printf("%d\n", ans);
}
return 0;
}