N*M矩阵,从F点出发,走完所有的Y点,每走一格花费1点电量,走到G点时,电量充满,D不可到达,问起始时的最小满电量可以走完所有Y,Y和G一共最多15个
先BFS出所有的F,Y,G之间的最短距离。
然后二分起始电量,对每个电量,做状压DP判断是否可行
#include "stdio.h"
#include "string.h"
#include "queue"
using namespace std;
int inf=0x3f3f3f3f;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct node
{
int x,y,step;
};
struct Mark
{
int x,y;
}mark[21];
char map[21][21];
int step[21][21],b[21],dp[70010][21],dis[21][21];
int cnt,aim,start,n,m;
int Min(int a,int b)
{
if (a<b) return a;else return b;
}
void bfs(int x,int y)
{
queue<node>q;
node cur,next;
int i;
memset(step,inf,sizeof(step));
step[x][y]=0;
cur.x=x;
cur.y=y;
cur.step=0;
q.push(cur);
while (!q.empty())
{
cur=q.front();
q.pop();
for (i=0;i<4;i++)
{
next.x=cur.x+dir[i][0];
next.y=cur.y+dir[i][1];
if (next.x<0 || next.x>=n || next.y<0 || next.y>=m) continue;
if (map[next.x][next.y]=='D') continue;
if (step[next.x][next.y]!=inf) continue;
next.step=cur.step+1;
step[next.x][next.y]=next.step;
q.push(next);
}
}
}
int DP(int key)
{
int i,j,k;
memset(dp,inf,sizeof(dp));
dp[b[start]][start]=0;
for (i=0;i<b[cnt];i++)
for (j=0;j<cnt;j++)
if ((b[j]&i)==b[j] && dp[i][j]!=inf)
{
for (k=0;k<cnt;k++)
if (k!=j && (b[k]&i)!=b[k] && dp[i][j]+dis[j][k]<=key)
{
dp[i+b[k]][k]=Min(dp[i+b[k]][k],dp[i][j]+dis[j][k]);
if (map[mark[k].x][mark[k].y]=='G') dp[i+b[k]][k]=0;
if (((i+b[k])&aim)==aim) return 1;
}
}
return 0;
}
int main()
{
int i,j,l,r,mid,ans;
b[0]=1;
for (i=1;i<=16;i++)
b[i]=b[i-1]*2;
while (scanf("%d%d",&n,&m)!=EOF)
{
if (n==0 && m==0) break;
cnt=0;
getchar();
for (i=0;i<n;i++)
gets(map[i]);
aim=0;
for (i=0;i<n;i++)
for (j=0;j<m;j++)
if (map[i][j]=='F' || map[i][j]=='Y' || map[i][j]=='G')
{
if (map[i][j]!='G') aim+=b[cnt];
if (map[i][j]=='F') start=cnt;
mark[cnt].x=i;
mark[cnt].y=j;
cnt++;
}
memset(dis,inf,sizeof(dis));
for (i=0;i<cnt;i++) // BFS出,F,Y,G之间的最短距离
{
bfs(mark[i].x,mark[i].y);
for (j=0;j<cnt;j++)
dis[i][j]=step[mark[j].x][mark[j].y];
}
l=0; r=n*m;
ans=-1;
while (l<=r) // 二分电量
{
mid=(l+r)/2;
if (DP(mid)==1)
{
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
printf("%d\n",ans);
}
return 0;
}