题意:给你一个n*m的图,机器人只能上下左右移动,移动一格消耗一点能量,F是起点,D是不可经过的点,S是空地,G是充能的站点,Y是必须经过的点,整个过程机器人必须让自己的能量尽可能的少,并且经过所有的Y,问机器人的最小能量容量是多少。
思路:因为‘G’和‘Y’的数量和T小于等于15,所以用这个来表示状态。
设'Y'的点数为Y。那么F标号为0,'Y'的点依次标号为1,2,....Y 。‘G’标号为Y+1,Y+2,....T。
状态S:第i位为1表示经过了第i-1个点。以此来二分答案。
设能量容量为k,dp[S][v]为经过状态S中的所有点,最后到达v的最大剩余能量。
状态转移方程:dp[S][v] = max(dp[S][v],dp[S-{v}][u] - G[u][v]) 如果dp[S][v] >= 0 且v > Y 的话,dp[S][v] = k。
我的代码:
#include<cstdio>
#include<iostream>
#include<map>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
typedef pair<int,int> P;
const int maxn = 15;
const int inf = 0x3f3f3f3f;
const int dx[4] = {1,-1,0,0};
const int dy[4] = {0,0,1,-1};
char maps[maxn][maxn];
int n,m,T,G[maxn][maxn];
int dp[1<<maxn][maxn];
map<P,int> M;
int Y;
struct Nod{
int x,y,step;
};
bool vis[maxn][maxn];
queue<Nod> que;
void init(){
M.clear();
int tmp = 1 << maxn;
//memset(G,-1,sizeof(G));
for(int i=0;i<maxn;i++) fill(G[i],G[i]+maxn,inf);
//for(int i=0;i<tmp;i++) fill(dp[i],dp[i]+maxn,inf);
}
void bfs(int x,int y,int s){
//cout<<x<<" "<<y<<" "<<s<<endl;
Nod cur,next;
memset(vis,0,sizeof(vis));
cur.x = x;cur.y = y;cur.step = 0;
que.push(cur);
vis[x][y] = true;
while(!que.empty()){
cur = que.front();que.pop();
//cout<<cur.x<<" "<<cur.y<<" "<<cur.step<<endl;
if(cur.step > 0 && (maps[cur.x][cur.y] == 'G' || maps[cur.x][cur.y] == 'Y')){
int pos = M[P(cur.x,cur.y)];
G[s][pos] = cur.step;
}
for(int i=0;i<4;i++){
next.x = cur.x + dx[i];
next.y = cur.y + dy[i];
next.step = cur.step + 1;
if(next.x < 0 || next.x >= n || next.y < 0 || next.y >= m || vis[next.x][next.y] || maps[next.x][next.y] == 'D') continue;
vis[next.x][next.y] = true;
que.push(next);
}
}
}
void build_graph(){
T = 1;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(maps[i][j] == 'Y') M.insert(make_pair(P(i,j),T++));
if(maps[i][j] == 'F') M.insert(make_pair(P(i,j),0));
}
}
Y = T - 1;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(maps[i][j] == 'G') M.insert(make_pair(P(i,j),T++));
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(maps[i][j] == 'F' || maps[i][j] == 'Y' || maps[i][j] == 'G'){
bfs(i,j,M[P(i,j)]);
}
}
}
}
bool check(int S){
for(int i=0;i<Y;i++){
if(!(S >> i & 1)) return false;
}
return true;
}
bool binSearch(int k){
int Ed = 1 << T;
bool flag;
memset(dp,-1,sizeof(dp));
dp[0][0] = k;
for(int S = 1; S < Ed ; S++){
flag = false;
for(int v = 1; v <= T ; v++){
if(!(S >> (v - 1) & 1)) continue;
int S0 = S - (1 << (v - 1));
if(S0 == 0){
dp[S][v] = max(dp[S][v],dp[0][0] - G[0][v]);
}
else{
for(int u = 1;u <= T;u++){
if(!(S0 >> (u - 1) & 1) || dp[S0][u] == -1) continue;
dp[S][v] = max(dp[S][v],dp[S0][u] - G[u][v]);
}
}
if(dp[S][v] >= 0){
flag = true;
if(v > Y) dp[S][v] = k;
}
}
if(check(S) && flag){
return true;
}
}
return false;
}
void solve(){
T -= 1;
int lb = 0,rb = 1000;
while(rb - lb > 1){
int mid = (lb + rb) >> 1;
if(binSearch(mid)) rb = mid;
else lb = mid;
}
if(rb == 1000) printf("-1\n");
else printf("%d\n",rb);
}
int main(){
while(~scanf("%d%d",&n,&m)){
if(n + m == 0) break;
init();
for(int i=0;i<n;i++) scanf("%s",maps[i]);
build_graph();
solve();
}
return 0;
}