测试地址:Prison Break
题目大意:一个
做法:本题需要用到状态压缩DP+BFS+二分答案。
首先,注意到电池容量大于某一个阈值时,都是可以完成任务的,反之就都不能完成,答案具有单调性,可以二分。接下来就是判定对于一个给定的电池容量
由于能量池和开关都是只能使用一次(使用多次没有意义),而且它们的数量很少(15个),所以可以套用经典的状压DP模型——TSP(旅行商)问题来解决,只需要BFS预处理出这些点两两之间需要消耗的能量,然后设
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,map[21][21],tot,p[21][2],t[21],final,start;
int g[21][21],dis[21][21],f[40010][21];
int q[410][2],head,tail;
bool vis[21][21];
char s[21];
struct forsort {int val,bit;} st[40010];
bool cmp(forsort a,forsort b)
{
return a.bit<b.bit;
}
void bfs(int s)
{
head=1,tail=1;
memset(vis,0,sizeof(vis));
q[1][0]=p[s][0],q[1][1]=p[s][1];
dis[q[1][0]][q[1][1]]=0;
vis[q[1][0]][q[1][1]]=1;
while(head<=tail)
{
int x=q[head][0],y=q[head][1];
if (x>1&&!map[x-1][y]&&!vis[x-1][y]) dis[x-1][y]=dis[x][y]+1,vis[x-1][y]=1,q[++tail][0]=x-1,q[tail][1]=y;
if (x<n&&!map[x+1][y]&&!vis[x+1][y]) dis[x+1][y]=dis[x][y]+1,vis[x+1][y]=1,q[++tail][0]=x+1,q[tail][1]=y;
if (y>1&&!map[x][y-1]&&!vis[x][y-1]) dis[x][y-1]=dis[x][y]+1,vis[x][y-1]=1,q[++tail][0]=x,q[tail][1]=y-1;
if (y<m&&!map[x][y+1]&&!vis[x][y+1]) dis[x][y+1]=dis[x][y]+1,vis[x][y+1]=1,q[++tail][0]=x,q[tail][1]=y+1;
head++;
}
for(int i=1;i<=tot;i++)
{
if (vis[p[i][0]][p[i][1]]) g[s][i]=dis[p[i][0]][p[i][1]];
else g[s][i]=-1;
}
}
bool check(int mid)
{
for(int i=0;i<(1<<tot);i++)
for(int j=1;j<=tot;j++)
f[i][j]=-1;
f[1<<(start-1)][start]=mid;
for(int i=2;i<=(1<<tot);i++)
{
int v=st[i].val,w[21]={0};
int x=v,j=1;
while(x)
{
if (x&1) w[++w[0]]=j;
x>>=1;j++;
}
for(j=1;j<=w[0];j++)
{
for(int k=1;k<=w[0];k++)
if (k!=j)
{
if (t[w[k]]==1&&g[w[k]][w[j]]!=-1&&f[v-(1<<(w[j]-1))][w[k]]!=-1)
f[v][w[j]]=max(f[v][w[j]],mid-g[w[k]][w[j]]);
else if (g[w[k]][w[j]]!=-1&&f[v-(1<<(w[j]-1))][w[k]]!=-1)
f[v][w[j]]=max(f[v][w[j]],f[v-(1<<(w[j]-1))][w[k]]-g[w[k]][w[j]]);
}
}
}
for(int i=0;i<(1<<tot);i++)
if ((i&final)==final)
{
for(int j=1;j<=tot;j++)
if (f[i][j]>=0) return 1;
}
return 0;
}
int main()
{
while(scanf("%d%d",&n,&m)&&n&&m)
{
final=0;
tot=0;
memset(map,0,sizeof(map));
for(int i=1;i<=n;i++)
{
scanf("%s",s);
for(int j=1;j<=m;j++)
{
if (s[j-1]=='D') map[i][j]=1;
if (s[j-1]=='F') p[++tot][0]=i,p[tot][1]=j,t[tot]=0,start=tot;
if (s[j-1]=='G') p[++tot][0]=i,p[tot][1]=j,t[tot]=1;
if (s[j-1]=='Y') p[++tot][0]=i,p[tot][1]=j,t[tot]=2,final+=1<<(tot-1);
}
}
for(int i=1;i<=tot;i++)
bfs(i);
for(int i=0;i<(1<<tot);i++)
{
st[i+1].val=i;
st[i+1].bit=0;
int x=i;
while(x)
{
if (x&1) st[i+1].bit++;
x>>=1;
}
}
sort(st+1,st+(1<<tot)+1,cmp);
int l=0,r=n*m+1;
while(l<r)
{
int mid=(l+r)>>1;
if (check(mid)) r=mid;
else l=mid+1;
}
if (l!=n*m+1) printf("%d
",l);
else printf("-1
");
}
return 0;
}