题意
一个人要出逃,需要从F点出发,访问所有的Y点才可以成功出逃,这个人可以拥有一个能量为V的背包,每移动一格消耗1点能量,到达G点的时候可以补充满能量。问最少需要携带一个多小的背包,才能成功出逃。
题解
第一眼看见这道题的时候,想的只是一个普通的BFS。但是在用优先队列实现的时候出现了一些问题,不太好判断优先访问哪个点。倘若不进行优先访问的选择,允许重复访问同一个点,那么无论是时间上还是空间上都是不可承受的。
看了题解才意识到这道题不是一道普通的BFS题,ORZ。。二分背包容量,BFS计算两点之间最短路,状压DP计算某个背包容量是否可行。
代码
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<string>
#include<set>
#include<map>
#include<bitset>
#define UP(i,l,h) for(int i=l;i<h;i++)
#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)
#define W(a) while(a)
#define INF 0x3f3f3f3f
#define LL long long
#define MAXN 8200
#define EPS 1e-10
#define MOD 100000000
using namespace std;
struct Node {
int x,y;
};
char mp[20][20];
int vis[20][20];
int dis[20][20][20][20];
int dp[20][67000];
int nodenum;
int dir[4][2]= {{1,0},{0,1},{-1,0},{0,-1}};
Node nodes[20];
int n,m;
int finalState;
int start;
void bfs(int x,int y) {
memset(vis,false,sizeof(vis));
queue<Node> que;
Node first;
first.x=x;
first.y=y;
que.push(first);
dis[first.x][first.y][first.x][first.y]=0;
W(!que.empty()) {
Node front=que.front();
que.pop();
vis[front.x][front.y]=true;
UP(i,0,4) {
Node newnode=front;
newnode.x+=dir[i][0];
newnode.y+=dir[i][1];
if(newnode.x>=n||newnode.y>=m||newnode.x<0||newnode.y<0)
continue;
if(vis[newnode.x][newnode.y])
continue;
if(mp[newnode.x][newnode.y]=='D')
continue;
dis[newnode.x][newnode.y][x][y]=dis[front.x][front.y][x][y]+1;
que.push(newnode);
}
}
}
bool check(int v) {
memset(dp,-1,sizeof(dp));
dp[start][1<<start]=v;
UP(k,0,1<<nodenum) {
UP(i,0,nodenum) {
if(dp[i][k]==-1||!(k&(1<<i)))
continue;
if((k&finalState)==finalState)
return true;
UP(j,0,nodenum) {
if(i==j||(k&(1<<j)))
continue;
int cost=dis[nodes[i].x][nodes[i].y][nodes[j].x][nodes[j].y];
if(cost==-1||cost>dp[i][k])
continue;
dp[j][k+(1<<j)]=max(dp[j][k+(1<<j)],dp[i][k]-cost);
if(mp[nodes[j].x][nodes[j].y]=='G')
dp[j][k+(1<<j)]=v;
}
}
}
return false;
}
int main() {
W(~scanf("%d%d",&n,&m)) {
if(n==0&&m==0)
break;
memset(dis,-1,sizeof(dis));
nodenum=0;
finalState=0;
UP(i,0,n) {
scanf("%s",mp[i]);
UP(j,0,m) {
if(mp[i][j]=='F') {
start=nodenum;
finalState+=(1<<nodenum);
nodes[nodenum].x=i;
nodes[nodenum++].y=j;
}
if(mp[i][j]=='Y') {
finalState+=(1<<nodenum);
nodes[nodenum].x=i;
nodes[nodenum++].y=j;
}
if(mp[i][j]=='G') {
nodes[nodenum].x=i;
nodes[nodenum++].y=j;
}
}
}
UP(i,0,nodenum) {
bfs(nodes[i].x,nodes[i].y);
}
int left=0,right=250;
int ans=INF;
W(left<=right) {
int mid=(left+right)/2;
if(check(mid)) {
right=mid-1;
ans=min(ans,mid);
} else {
left=mid+1;
}
}
if(ans==INF) {
puts("-1");
} else {
printf("%d\n",ans);
}
}
}
/*
5 5
GDDDS
SSDFD
SYGDS
SGGYS
SSYSS
1 4
FYGY
*/