原题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1072
分析:主要思想还是BFS,与简单BFS不同的是,这个题目用一个Left存放最高的剩余时间,凡是后到的并且小于这个位置Left的都不可能成为最终解,“剪枝”剪掉,同时还有一点非常重要:四号位只能经过一次!!!不然扩张的时候会利用四号位刷新Left,队列不停入队,最终超时,因此,第一次经过四号位时,到最后把Left置为-1,表示已经经过该位置。其他的都跟基本BFS一样了。
代码如下:
#include <stdio.h>
#include <queue>
using namespace std;
int Left[10][10];
int maze[10][10];
struct Pos{
int x,y;
int time;
int used;
};
queue <Pos> Q;
int gonext[][2]={
1,0,
-1,0,
0,1,
0,-1
};
int DFS(int n,int m,int end_x,int end_y)
{
while(Q.empty()==false)
{
Pos N=Q.front();
Q.pop();
int i;
for(i=0;i<4;i++)
{
int nx=N.x+gonext[i][0];
int ny=N.y+gonext[i][1];
int nt=N.time-1;
int nu=N.used+1;
if(nx==end_x&&ny==end_y&&nt>0) return nu;
//如果超出范围,或者遇到墙,或者时间为0,或者又走到四号位,则跳过
if(nx<1||nx>n||ny<1||ny>m||nt==0) continue;
if(maze[nx][ny]==0||Left[nx][ny]==-1)continue;
//如果第一次走到四号位,修改剩余时间为6
if(maze[nx][ny]==4)
{
nt=6;
}
//如果剩余时间小于之前的,则跳过
if(nt<=Left[nx][ny]) continue;
Pos tmp;
tmp.x=nx;
tmp.y=ny;
tmp.time=nt;
tmp.used=nu;
Q.push(tmp);
Left[nx][ny]=nt;
//如果当前是四号位,最后把剩余时间标记置为-1
if(maze[nx][ny]==4) Left[nx][ny]=-1;
}
}
return -1;
}
int main(int argc, char** argv) {
int n,m;
int T;
scanf("%d",&T);
while(T--)
{ scanf("%d%d",&n,&m);
int i,j;
int sx,sy,ex,ey;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%d",&maze[i][j]);
Left[i][j]=0;
if(maze[i][j]==2)
{
sx=i;
sy=j;
}
if(maze[i][j]==3)
{
ex=i;
ey=j;
}
}
}
while(Q.empty()==false) Q.pop();
Pos st;
st.x=sx;
st.y=sy;
st.time=6;
st.used=0;
Q.push(st);
Left[sx][sy]=6;
int ans=DFS(n,m,ex,ey);
printf("%d\n",ans);
}
return 0;
}