题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=3681
囧,BFS+二分+DFS。
一开始懒,想直接BFS过这题,结果TLE还想着用剪枝,还是TLE。
无奈,用想到的第二种方法,bfs预处理点与点之间的距离,然后二分枚举长度,dfs查询是否能够逃出。
刚写完的时候一直WA,不明所以。
于是写了个随机,然后暴力对跑,终于发现错误。
囧。。。 有一种数据过不了。。。
3 3
GDF
DDS
YSS
原因很简单,表示两点之间的距离,我预处理时将之设为-1。。。
也就是,假如两点之间没有通路,那么他们之间的距离就是-1 。。。
于是F到G成了-1步。。。 G到Y也成了-1步。。。
可想而知, F到Y成了-2步。。。
#include<cstdio>
#include<cstring>
int dir[32][32];
int y,g,n,m;
char mp[16][16];
int rmp[16][16],rx,ry;
struct Point{
int x,y;
Point(){}
Point(int xx,int yy){
x=xx;
y=yy;
}
}que[5000];
const int fx[]={0,0,1,-1};
const int fy[]={1,-1,0,0};
void bfs(int x,int y){
int vis[16][16];
int s,t,k;
Point no,nx;
memset(vis,-1,sizeof(vis));
que[s=t=0]=Point(x,y);
vis[x][y]=0;
while(s<=t){
no=que[s++];
if(mp[no.x][no.y]!='S'){
dir[rmp[x][y]][rmp[no.x][no.y]]=vis[no.x][no.y];
}
for(k=0;k<4;k++){
nx.x=no.x+fx[k];
nx.y=no.y+fy[k];
if(nx.x<0 || nx.y<0 || nx.x>=n || nx.y>=m) continue;
if(vis[nx.x][nx.y]!=-1 || mp[nx.x][nx.y]=='D') continue;
vis[nx.x][nx.y]=vis[no.x][no.y]+1;
que[++t]=nx;
}
}
}
int has[31];
int dfs(int x,int now,int len,int num){
if(num==y-1) return 1;
for(int i=1;i<y;i++){
if(now+dir[x][i]<=len && has[i]==0 && dir[x][i]!=-1){
has[i]=1;
if(dfs(i,now+dir[x][i],len,num+1)) return 1;
has[i]=0;
}
}
for(int i=30;i>g;i--){
if(now+dir[x][i]<=len && has[i]==0 && dir[x][i]!=-1){
has[i]=1;
if(dfs(i,0,len,num)) return 1;
has[i]=0;
}
}
return 0;
}
int BitFind(){
int l=0,r=55000,mid;
while(l<=r){
mid=(l+r)>>1;
memset(has,0,sizeof(has));
has[0]=1;
if(dfs(0,0,mid,0)){
r=mid-1;
}
else {
l=mid+1;
}
}
return l;
}
int never(){
int i;
for(i=1;i<y;i++){
if(dir[0][i]==-1){
return 1;
}
}
return 0;
}
void INIT(){
int i,j;
y=1;
g=30;
for(i=0;i<n;i++){
scanf("%s",mp[i]);
for(j=0;j<m;j++){
if(mp[i][j]=='F'){
rx=i;
ry=j;
rmp[i][j]=0;
}
else if(mp[i][j]=='Y'){
rmp[i][j]=y++;
}
else if(mp[i][j]=='G'){
rmp[i][j]=g--;
}
else if(mp[i][j]=='D'){
rmp[i][j]=-1;
}
else{
rmp[i][j]=0;
}
}
}
memset(dir,-1,sizeof(dir));
for(i=0;i<n;i++){
for(j=0;j<m;j++){
if(rmp[i][j]>0 || mp[i][j]=='F'){
bfs(i,j);
/* // 输出预处理的结果,也就是(i,j)到(ii,jj)的步数。
printf("--- %d,%d\n",i,j);
for(int ii=0;ii<n;ii++){
for(int jj=0;jj<m;jj++){
if(mp[ii][jj]!='D' && mp[ii][jj]!='S'){
printf("-> %d,%d ..... %d \n",ii,jj,dir[rmp[i][j]][rmp[ii][jj]]);
}
}
}
*/
}
}
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
if(n==0) break;
INIT();
if(never()){
puts("-1");
}
else{
printf("%d\n",BitFind());
}
}
return 0;
}
/*
7 7
SSSSDFS
GDSGDSS
DSDDSSG
GSSSGSS
SSSSSSS
SSSSDGS
DDYSDSS
*/