题目大意:有一个机器人想越狱,越狱的要求是将所有的电网开关关掉。现在给出一个地图,’S’表示空地,‘F‘表示起始地点,‘G‘表示充电池,‘D‘表示禁地,‘Y‘开关
充电池可以将机器人的电充满。机器人每走一格就需要耗掉1点能量,问机器人的起始能量至少要是多少才可以逃出监狱
解题思路:先将所有能连通的点连通起来,将充电池和开关抽象出来,压缩成一个状态
求出每个充电池和开关之间的两两间的最短距离,接着二分枚举机器人的初始电量,再暴力枚举机器人行动的每种情况(dfs)
这里已经求出了充电池和开关之间的最短距离了,那怎样判断经过了充电池是否要充电呢
因为枚举的时候,是只枚举机器人到充电池和开关的最短路径的,如果中途遇到了充电池,也就是说最短路的路途中有充电池,这种情况经过是不进行充电的
而如果是枚举的下一点是充电池的话,这种情况是直接充电的
这样就把经过充电池该不该充电的情况给考虑进去了
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define N 20
#define M 410
#define S 2010
char g[N][N];
int head[M], u[S], v[S], Next[S], id[N][N], dis[N][N], x[N], y[N];
int n, m, num, cnt, final;
void add_edgs(int s, int e) {
u[cnt] = s;
v[cnt] = e;
Next[cnt] = head[s];
head[s] = cnt++;
}
void init() {
memset(head, -1, sizeof(head));
memset(id, -1, sizeof(id));
memset(dis, -1, sizeof(dis));
cnt = 0; num = 1; final = 0;
for (int i = 0; i < n; i++)
scanf("%s", g[i]);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (g[i][j] == 'D')
continue;
else if (g[i][j] == 'F') {
x[0] = i;
y[0] = j;
id[i][j] = 0;
}
else if (g[i][j] == 'G') {
x[num] = i;
y[num] = j;
id[i][j] = num++;
}
else if (g[i][j] == 'Y') {
x[num] = i;
y[num] = j;
final |= (1 << num);
id[i][j] = num++;
}
if (i > 0 && g[i - 1][j] != 'D')
add_edgs(i * m + j, (i - 1) * m + j);
if (j > 0 && g[i][j - 1] != 'D')
add_edgs(i * m + j, i * m + j - 1);
if (i + 1 < n && g[i + 1][j] != 'D')
add_edgs(i * m + j, (i + 1)* m + j);
if (j + 1 < m && g[i][j + 1] != 'D')
add_edgs(i * m + j, i * m + j + 1);
}
}
}
struct Node {
int pos, dis;
}n1, n2;
bool vis[M];
void bfs(int s) {
queue<struct Node> q;
memset(vis, 0, sizeof(vis));
n1.pos = s;
n1.dis = 0;
q.push(n1);
vis[s] = 1;
while (!q.empty()) {
n2 = q.front();
q.pop();
int t = n2.pos;
if (id[t / m][t % m] != -1)
dis[id[t / m][t % m]][id[s / m][s % m]] = n2.dis;
for (int i = head[t]; i != -1; i = Next[i]) {
if (vis[v[i]])
continue;
n1.pos = v[i];
n1.dis = n2.dis + 1;
q.push(n1);
vis[v[i]] = 1;
}
}
}
bool mark[N];
bool dfs(int pos, int state, int power, int all_power) {
if ((state & final) == final)
return true;
for (int i = 1; i < num; i++) {
if (mark[i] || dis[pos][i] == -1)
continue;
if (power >= dis[pos][i]) {
if (g[x[i]][y[i]] == 'G') {
mark[i] = 1;
if (dfs(i, state | (1 << i), all_power, all_power))
return true;
mark[i] = 0;
}
else {
mark[i] = 1;
if (dfs(i, state | (1 << i), power - dis[pos][i], all_power))
return true;
mark[i] = 0;
}
}
}
return false;
}
void solve() {
for (int i = 0; i < num; i++)
bfs(x[i] * m + y[i]);
bool flag = false;
int ans = -1;
for (int i = 1; i < num; i++)
if (g[x[i]][y[i]] == 'Y' && dis[id[x[i]][y[i]]][0] == -1) {
flag = true;
break;
}
if (!flag) {
int l = 0, r = n * m * (num - 1);
while (l <= r) {
int mid = (l + r) / 2;
memset(mark, 0, sizeof(mark));
mark[0] = 1;
if (dfs(0, 1, mid, mid)) {
ans = mid;
r = mid - 1;
}
else {
l = mid + 1;
}
}
}
printf("%d\n", ans);
}
int main() {
while (scanf("%d%d", &n, &m) != EOF && n + m) {
init();
solve();
}
return 0;
}