本人水平有限,仅供学习,如有发现错误,感谢指出。
描述
已知一张地图(以二维矩阵的形式表示)以及佐助和鸣人的位置。地图上的每个位置都可以走到,只不过有些位置上有大蛇丸的手下,需要先打败大蛇丸的手下才能到这些位置。鸣人有一定数量的查克拉,每一个单位的查克拉可以打败一个大蛇丸的手下。假设鸣人可以往上下左右四个方向移动,每移动一个距离需要花费1个单位时间,打败大蛇丸的手下不需要时间。如果鸣人查克拉消耗完了,则只可以走到没有大蛇丸手下的位置,不可以再移动到有大蛇丸手下的位置。佐助在此期间不移动,大蛇丸的手下也不移动。请问,鸣人要追上佐助最少需要花费多少时间?
输入
输入的第一行包含三个整数:M,N,T。代表M行N列的地图和鸣人初始的查克拉数量T。0 < M,N < 200,0 ≤ T < 10
后面是M行N列的地图,其中@代表鸣人,+代表佐助。*代表通路,#代表大蛇丸的手下。
输出
输出包含一个整数R,代表鸣人追上佐助最少需要花费的时间。如果鸣人无法追上佐助,则输出-1。
题目链接 : 传送门(点我)
分析:
- 朴素的广搜中,队列中存储了哪些信息? 1.节点坐标 2.节点step ,所以说,队列中节点存储的是状态。
- 在该题中,节点的状态是什么?1.坐标 2.步数 3.查克拉能量
那么这里要用三维数组来判重,为什么?
因为存在通过相同点时,而查克拉此时不同,导致的结果是不同的,所以,我们判的其实是状态。
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 210
char mp[MAXN][MAXN];
int vis[MAXN][MAXN][MAXN];
int xx[4]={
0,0,-1,1},yy[4]={
-1,1,0,0};
int m,n,c;
struct node{
int x,y;
int t;//left 查克拉
int time;
};
node s,f;//start final
queue<node>q;
int main()
{
cin>>m>>n>>c;
for(int i=0;i<m;i++){
//initialization
for(int j=0;j<n;j++){
cin>>mp[i][j];
if(mp[i][j]=='@')s.x=i,s.y=j,s.time=0,s.t=c;//start
if(mp[i][j]=='+')f.x=i,f.y=j,f.time=-1;//final
}
}
q.push(s);vis[s.x][s.y][s.t]=1;
while(q.size()!=0){
node t = q.front();
q.pop();
if(t.x==f.x&&t.y==f.y){
f.time=t.time;break;
}
for(int i=0;i<4;i++){
node z;
z.x=t.x+xx[i];z.y=t.y+yy[i];z.time=t.time+1;z.t=t.t;
if(z.x<0||z.x>=m||z.y<0||z.y>=n||vis[z.x][z.y][z.t]==1)continue;//cross the border
if(mp[z.x][z.y]=='#'){
//go to 查克拉
if(z.t>=1)z.t--;//查克拉reduce
else continue; // 查克拉 not enough
}
vis[z.x][z.y][z.t]=1;
q.push(z);
}
}
return cout<<f.time<<endl,0;
}