题意:机器人逃狱,需把所有开关Y遍历才能成功,G可以使机器人充满电(只能使用一次,也可暂时不用),D不能走,S为空,走一步要消耗一格电,没电无法继续走,问机器人能逃出去起始需要具有的最少电量。
思路:把G,Y抽离出来建立一张图,预处理任意两点的最短距离(bfs),G和Y都只通过一次(这里并不意味着走到G就必须用掉,很明显由于是最短路径,用掉是最优解,有些G可能包含在最短路径之中通过而没有用),于是就是一个TSP问题,二分答案。
TSP:dp[s][i]表示已走节点为s,且最后走的是i,枚举已走节点j(j!=i),dp[s][i]=max(dp[s-j][k]+dis),k为s-j集合中已走节点。s可有小到大遍历,因为处理s时,s之前的状态都已经处理过。
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#define inf 10000000
#define pi acos(-1.0)
#define eps 1e-8
#define seed 131
using namespace std;
typedef pair<int,int> pii;
typedef pair<pii,int> pe;
typedef unsigned long long ULL;
typedef long long LL;
const int maxn=100005;
char g[16][16];
int n,m;
int dis[16][16][16][16];
int dir[4][2]={{0,1},{1,0},{-1,0},{0,-1}};
struct Node
{
int x,y;
}node[18];
int dp[18][1<<18];
int num;
int mid;
int ny,ng;
void bfs(int r0,int c0);
bool TSP(int c,int s);
int main()
{
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0)
break;
ny=0,ng=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>g[i][j];
if(g[i][j]=='Y')
ny++;
if(g[i][j]=='G')
ng++;
}
}
num=ny+ng+1;
int e1=1;
int e2=0;
memset(dis,-1,sizeof(dis));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(g[i][j]=='F'||g[i][j]=='G'||g[i][j]=='Y')
{
if(g[i][j]=='F')
{
node[0].x=i;
node[0].y=j;
}
if(g[i][j]=='Y')
{
node[e1].x=i;
node[e1++].y=j;
}
if(g[i][j]=='G')
{
node[ny+1+e2].x=i;
node[ny+1+e2].y=j;
e2++;
}
bfs(i,j);
}
}
}
int l=0,r=300;
bool flag=false;
while(l<r)
{
mid=(l+r)/2;
dp[0][1]=mid;
if(TSP(0,1))
{
flag=true;
r=mid;
}
else
l=mid+1;
}
if(!flag)
printf("-1\n");
else
printf("%d\n",l);
}
return 0;
}
bool ok(int s)
{
for(int i=1;i<=ny;i++)
{
if(!((1<<i)&s))
return false;
}
return true;
}
bool TSP(int c,int s)
{
for(int i=s+1;i<(1<<num);i++)
{
for(int j=0;j<num;j++)
{
if(!((1<<j)&i))
continue;
dp[j][i]=-1;
for(int k=0;k<num;k++)
{
if(k==j||(!((1<<k)&i))||dis[node[j].x][node[j].y][node[k].x][node[k].y]==-1)
continue;
dp[j][i]=max(dp[j][i],dp[k][i^(1<<j)]-dis[node[j].x][node[j].y][node[k].x][node[k].y]);
if(dp[j][i]<0)
continue;
if(g[node[j].x][node[j].y]=='G')
dp[j][i]=mid;
if(dp[j][i]>=0&&ok(i))
return true;
}
}
}
return false;
}
void bfs(int r0,int c0)
{
bool vis[16][16];
memset(vis,0,sizeof(vis));
queue<pe>que;
que.push(pe(pii(r0,c0),0));
vis[r0][c0]=1;
dis[r0][c0][r0][c0]=0;
while(!que.empty())
{
pe p=que.front();
que.pop();
for(int i=0;i<4;i++)
{
int r=p.first.first+dir[i][0];
int c=p.first.second+dir[i][1];
if(r>=1&&r<=n&&c>=1&&c<=m&&vis[r][c]==0&&g[r][c]!='D')
{
if(g[r][c]=='F'||g[r][c]=='G'||g[r][c]=='Y')
{
dis[r0][c0][r][c]=p.second+1;
}
vis[r][c]=1;
que.push(pe(pii(r,c),p.second+1));
}
}
}
}