5 5 GDDSS SSSFS SYGYS SGSYS SSYSS 0 0
4
/*
题意: D不能走,s可以走,Y是要到达的地方(所以都要经过),G是加油的地方(一个G只能加一次由)
F是起点,求最少需要多少时间才可以从F经过所有的Y
思路: Y是必到的地方,G是选择性到的,用状压
1:先bfs求出任意Y,F,G 的最短距离
2:二分答案,然后用状压DP判断是否可行
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<map>
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define MID(x,y) ((x+y)>>1)
#define eps 1e-8
typedef __int64 ll;
using namespace std;
#define INF 0x3f3f3f3f
#define N 16
int dp[1<<N][N];
int all,k;
int dis[N][N][N][N];
int n,m;
struct stud{
stud(){};
stud(int xx,int yy):x(xx),y(yy),step(0){};
int x,y;
int step;
}f[N];
queue<stud>q;
int step[4][2]={1,0,-1,0,0,1,0,-1};
char c[N][N];
int vis[N][N];
int start;
bool judge(int x,int y)
{
if(x>=0&&x<n&&y>=0&&y<m)
return true;
return false;
}
void bfs(int sx,int sy)
{
int i,j;
while(!q.empty()) q.pop();
memset(vis,0,sizeof(vis));
stud cur(sx,sy);
cur.step=0;
q.push(cur);
stud next;
vis[sx][sy]=1;
while(!q.empty())
{
cur=q.front();
q.pop();
for(i=0;i<4;i++)
{
int xx=cur.x+step[i][0];
int yy=cur.y+step[i][1];
if(!judge(xx,yy)) continue;
if(c[xx][yy]=='D') continue;
if(vis[xx][yy]) continue;
next.x=xx;
next.y=yy;
next.step=cur.step+1;
dis[sx][sy][xx][yy]=next.step;
vis[xx][yy]=1;
q.push(next);
}
}
}
inline int getdis(int i,int j)
{
return dis[f[i].x][f[i].y][f[j].x][f[j].y];
}
bool DP(int mid)
{
int i,j;
int len=1<<k,ans=-1;
memset(dp,-1,sizeof(dp));
dp[1<<start][start]=mid; //起点
int cur;
for(cur=0;cur<len;cur++)
for(i=0;i<k;i++)
{
if(!(cur&(1<<i))) continue;
if((cur&all)==all) ans=max(ans,dp[cur][i]);
if(dp[cur][i]<=0) continue;
for(j=0;j<k;j++)
{
if(cur&(1<<j)) continue;
int next=cur|(1<<j);
int temp=getdis(i,j);
if(temp>dp[cur][i]) continue;
dp[next][j]=max(dp[next][j],dp[cur][i]-temp);
if(c[f[j].x][f[j].y]=='G')
dp[next][j]=mid;
}
}
return ans>=0;
}
void solve()
{
int i,j;
int le=0,ri=250,mid; //二分答案
int ans=-1;
while(le<=ri)
{
mid=(le+ri)>>1;
if(DP(mid))
{
ans=mid;
ri=mid-1;
}
else
le=mid+1;
}
printf("%d\n",ans);
}
int main()
{
int i,j;
while(scanf("%d%d",&n,&m),n+m)
{
for(i=0;i<n;i++)
scanf("%s",c[i]);
k=0;
all=0;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(c[i][j]=='F')
{
all|=1<<k;
start=k; //起点
f[k++]=stud(i,j);
}
else
if(c[i][j]=='G')
{
f[k++]=stud(i,j);
}
else
if(c[i][j]=='Y')
{
all|=1<<k; //要到达的状态是all
f[k++]=stud(i,j);
}
memset(dis,INF,sizeof(dis));
for(i=0;i<k;i++)
bfs(f[i].x,f[i].y);
solve();
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU 3681 Prison Break(bfs+二分+状压DP)
原文地址:http://blog.csdn.net/u014737310/article/details/46778045