題意:
機器人從F出發,走到G可以充滿電,走到Y關掉開關,D不能走進,要求把所有開關關掉,且機器人存儲的電量最少,並求出該最小電量。
分析:
把F,G,Y三種類型的點找出來,進行討論,首先bfs處理出來各個點之間的最短路。現在題目就變成了:求一幅圖中滿足走遍所有Y點的條件,機器人存儲的電量最少。
由於點最多隻有15個,狀壓dp來處理。二分機器人的儲電量,每次用dp來做判定條件。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n,m;
char map[22][22];
int dist[22][22],vis[22][22];
int dx[] = {0,0,-1,1};
int dy[] = {1,-1,0,0};
int dp[22][1<<16];
struct node {
int x,y,step;
char c;
}q[1111],p[20];
int head,tail,cnt,st,numY;
int bfs(int x,int y,int xx,int yy) {
head = 0; tail = 0;
memset(vis,0,sizeof(vis));
q[head].x = x;
q[head].y = y;
q[head++].step = 0;
vis[x][y] = 1;
while(head != tail) {
node t = q[tail++];
node tt;
if(t.x == xx && t.y == yy) {
return t.step;
}
for(int i=0; i<4; i++) {
tt.x = t.x + dx[i];
tt.y = t.y + dy[i];
if(tt.x<0 || tt.x>=n || tt.y<0 || tt.y >=m || map[tt.x][tt.y] == 'D' || vis[tt.x][tt.y] ) continue;
tt.step = t.step + 1;
vis[tt.x][tt.y] = 1;
q[head++] = tt;
}
}
return -1;
}
void getdist() {
for(int i=0; i<cnt; i++) {
for(int j=i; j<cnt; j++) {
if(i == j) dist[i][j] = 0;
else {
dist[i][j] = bfs(p[i].x,p[i].y,p[j].x,p[j].y);
dist[j][i] = dist[i][j];
}
}
}
}
int getY(int x) {
int id = 0;
int num = 0;
while(x) {
if((x & 1) && p[id].c == 'Y') num ++;
x = x >> 1;
id ++;
}
return num;
}
int judge(int va) {
memset(dp,-1,sizeof(dp));
int total = 1 << cnt;
dp[st][1 << st] = va;
for(int j=0; j<total; j++) {
if((j & (1 << st)) == 0) continue;
for(int i=0; i<cnt; i++) {
if(i == st) continue;
for(int k=0; k<cnt; k++) {
if(dist[i][k] == -1) continue;
if(dist[i][k] <= dp[k][j ^ (1 << i)]) {
if(p[i].c == 'G') dp[i][j] = va;
else dp[i][j] = max(dp[i][j],dp[k][j ^ (1 << i)] - dist[i][k]);
}
}
}
}
for(int j=0; j<total; j++) {
if((j & (1 << st)) == 0) continue;
if(getY(j) == numY) {
for(int i=0; i<cnt; i++) {
if(p[i].c == 'Y' && dp[i][j] != -1) return 1;
}
}
}
return 0;
}
void solve() {
getdist();
int l = 1, r = 250, mid;
int minn = 251;
while(l <= r) {
mid = (l + r) >> 1;
if(judge(mid)) {
minn = min(minn,mid);
r = mid - 1;
} else l = mid + 1;
}
if(minn == 251) puts("-1");
else printf("%d\n",minn);
}
int main() {
while(scanf("%d%d",&n,&m)) {
if(n == 0 && m == 0) break;
cnt = 0; numY = 0;
for(int i=0; i<n; i++) scanf("%s",map[i]);
for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
if(map[i][j] == 'F') {
p[cnt].x = i; p[cnt].y = j;
p[cnt].c = 'F';
st = cnt;
cnt ++;
}
if(map[i][j] == 'G') {
p[cnt].x = i; p[cnt].y = j;
p[cnt].c = 'G';
cnt++;
}
if(map[i][j] == 'Y') {
numY ++;
p[cnt].x = i; p[cnt].y = j;
p[cnt].c = 'Y';
cnt++;
}
}
}
solve();
}
return 0;
}