題目大意:有一個(gè)機(jī)器人想越獄,越獄的要求是將所有的電網(wǎng)開關(guān)關(guān)掉。現(xiàn)在給出一個(gè)地圖,’S’表示空地,‘F‘表示起始地點(diǎn),‘G‘表示充電池,‘D‘表示禁地,‘Y‘開關(guān)
充電池可以將機(jī)器人的電充滿。機(jī)器人每走一格就需要耗掉1點(diǎn)能量,問機(jī)器人的起始能量至少要是多少才可以逃出監(jiān)獄
解題思路:先將所有能連通的點(diǎn)連通起來,將充電池和開關(guān)抽象出來,壓縮成一個(gè)狀態(tài)
求出每個(gè)充電池和開關(guān)之間的兩兩間的最短距離,接著二分枚舉機(jī)器人的初始電量,再暴力枚舉機(jī)器人行動(dòng)的每種情況(dfs)
這里已經(jīng)求出了充電池和開關(guān)之間的最短距離了,那怎樣判斷經(jīng)過了充電池是否要充電呢
因?yàn)槊杜e的時(shí)候,是只枚舉機(jī)器人到充電池和開關(guān)的最短路徑的,如果中途遇到了充電池,也就是說最短路的路途中有充電池,這種情況經(jīng)過是不進(jìn)行充電的
而如果是枚舉的下一點(diǎn)是充電池的話,這種情況是直接充電的
這樣就把經(jīng)過充電池該不該充電的情況給考慮進(jìn)去了
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define N 20
#define M 410
#define S 2010char 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;
}
總結(jié)
以上是生活随笔為你收集整理的HDU - 3681 Prison Break(状态压缩 + 最短路)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。