题意:开始能量包能提供走K步的能量,从F点出发要经过每一个Y点,通过G点时能充满能量包。且不能经过D点
求最小的K。
Y+G的个数最多有15个
因为只有15个有用的点预处理出两两的距离,二分K值 状压搞一搞
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PI;
char s[123][123];
struct node
{
int x,y,step;
node(){};
void hehe(int _x,int _y)
{
x=(_x),y=(_y);
}
}pg[20],py[20];
int n,m,gnum=0,ynum=0;
int xx[4]={0,0,-1,1};
int yy[4]={1,-1,0,0};
int vis[20][20],dis[20][20];
int star[123];
void gao(int x,int y)
{
dis[s[x][y]][s[x][y]]=0;
memset(vis,0,sizeof(vis));
queue<node> q;
vis[x][y]=1;
node fro;fro.x=x,fro.y=y;fro.step=0;
q.push(fro);
while(!q.empty())
{
fro=q.front();
q.pop();
for(int i=0;i<4;i++){
int fx=fro.x+xx[i];
int fy=fro.y+yy[i];
if(fx>=n||fx<0||fy<0||fy>=m||vis[fx][fy]||s[fx][fy]=='D') continue;
node rear;
rear.x=fx;rear.y=fy;rear.step=fro.step+1;
vis[fx][fy]=1;
if(s[fx][fy]<=gnum+ynum)
{
dis[s[fx][fy]][s[x][y]]=rear.step;
dis[s[x][y]][s[fx][fy]]=rear.step;
}
q.push(rear);
}
}
}
int dp[(1<<16)][16];
int orz(int need)
{
memset(dp,-1,sizeof(dp));
dp[1][0]=need;
for(int i=1;i< 1<<(ynum+gnum+1);i++)
{
for(int j=0;j<ynum+gnum+1;j++)//j star
{
if(dp[i][j]<=-1||i&(1<<j)==0) continue;
if((i&((1<<(ynum+1))-1)) == ((1<<(ynum+1))-1))
return 1;
for(int k=0;k<ynum+gnum+1;k++)//end
{
if(i&(1<<k)||dis[j][k]==-1) continue;
dp[i|(1<<k)][k]=max(dp[i|(1<<k)][k],dp[i][j]-dis[j][k]);
if(dp[i|(1<<k)][k]>=0 && k>ynum)
dp[i|(1<<k)][k]=need;
}
}
}
return 0;
}
int main()
{
while(scanf("%d%d",&n,&m),n+m)
{
gnum=0,ynum=0;
int sx,sy;
for(int i=0;i<n;i++)
{
cin>>s[i];
for(int j=0;j<m;j++){
if(s[i][j]=='F')
sx=i,sy=j;
else if(s[i][j]=='G')
{
pg[gnum++].hehe(i,j);
}
else if(s[i][j]=='Y'){
py[ynum++].hehe(i,j);
}
}
}
s[sx][sy]=0;
for(int i=0;i<gnum;i++) s[pg[i].x][pg[i].y]=ynum+i+1;
for(int i=0;i<ynum;i++) s[py[i].x][py[i].y]=i+1;
memset(dis,-1,sizeof(dis));
gao(sx,sy);
for(int i=0;i<gnum;i++)
gao(pg[i].x,pg[i].y);
for(int i=0;i<ynum;i++)
gao(py[i].x,py[i].y);
int flag=0;
for(int i=0;i<=ynum;i++)
{
for(int j=1;j<=ynum;j++){
if(dis[i][j]==-1) flag=1;
}
}
if(flag)
{
printf("-1\n");
continue;
}
int l=0,r=3000,ans=-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(orz(mid)){
r=mid-1;
ans=mid;
}
else l=mid+1;
}
cout<<ans<<endl;
}
return 0;
}
/*
3 3
FYS
SYS
SGY
*/