HDU 1072 Nightmare(BFS)
http://acm.hdu.edu.cn/showproblem.php?pid=1072
题意:
有一个N*M的迷宫,你要从起点2走到终点3,且你身上有炸弹,这个炸弹6分钟后爆炸,你在迷宫中每走一步需要1分钟,且迷宫中有重置装置(4格子),可以使得你的炸弹爆炸时间重新变为6.不过不论是你到达终点还是你到达重置装置的地方,你身上的炸弹爆炸时间一定要>=1分钟才行,要不你就失败.重置装置可以无限使用,且迷宫中为1的格子是障碍,为0的格子是空(可以走).输出你走到终点的最短时间.
分析:
又是一道设计状态的BFS题目,由于题目中每个格子可能重复走(因为要去用重置装备),所以我们设计状态如下:
struct Node
{
int r, c;//当前坐标
int time;//当前炸弹还剩time分钟爆炸
int dist;//走到当前r,c,time状态所花的时间(即所走的距离)
}Q[maxn]
所以我们用dist[r][c][time](初值-1,表示该状态还没到达) 表走到状态(r,c,time)所花的最少时间(步数).
因为所有格子都是可以重复走的,但是当我重复走这个格子的时候如果具有一个更大的time值,我就可能走得更多的格子,出现不同的结果.所以time要作为状态的一维.如果剩余time更多,当然更好,但是有可能我们剩余time少的状态也可以到达终点且dist可能更少.所以time少的状态我们也不可以抛弃(即我们不能只保存time最大的那个r和c)
AC代码:
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=10000+100;
int N,M;
int sr,sc,er,ec;//起点终点坐标
int dist[10][10][10];
int map[10][10];
int dr[]={-1,1,0,0};//上下左右
int dc[]={0,0,-1,1};
struct Node
{
int r,c,time,dist;
Node(){}
Node(int r,int c,int time,int dist):r(r),c(c),time(time),dist(dist){}
}Q[maxn];
int BFS()
{
memset(dist,-1,sizeof(dist));
int front=0,tail=1;
Q[front]=Node(sr,sc,6,0);
dist[sr][sc][6]=0;
while(front<tail)
{
Node node=Q[front];
for(int d=0;d<4;d++)
{
int nr=node.r+dr[d], nc=node.c+dc[d];
if(!(nr>=0&&nr<N&&nc>=0&&nc<M) || map[nr][nc]==0) continue;//非法坐标
int ntime = map[nr][nc]==4?6: (node.time-1);
int ndist = node.dist+1;
if(dist[nr][nc][ntime]==-1 || dist[nr][nc][ntime]>ndist)
{
dist[nr][nc][ntime]=ndist;
if(ntime>1) Q[tail++]=Node(nr,nc,ntime,ndist); //错误,这里没加前面的if,ntime如果==1,它的后继的time肯定为0,没意义
if(nr==er&&nc==ec) return ndist; //不用遍历全图,这就是最短的距离
}
}
front++;
}
return -1; //错误,忘写了返回值,出现诡异错误
}
int main()
{
int T; scanf("%d",&T);
while(T--)
{
scanf("%d%d",&N,&M);
for(int i=0;i<N;i++)
for(int j=0;j<M;j++)
{
scanf("%d",&map[i][j]);
if(map[i][j]==2)
{
sr=i, sc=j;
map[i][j]=1;
}
else if(map[i][j]==3)
{
er=i, ec=j;
map[i][j]=1;
}
}
int ans=BFS();
printf("%d\n",ans);
}
return 0;
}