3681 Prison Break(狀態壓縮 + 最短路)
阿新 • • 發佈:2019-02-02
題目大意:有一個機器人想越獄,越獄的要求是將所有的電網開關關掉。現在給出一個地圖,’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;
}