鸣人和佐助

鸣人和佐助

题目链接

题目描述

佐助被大蛇丸诱骗走了,鸣人在多少时间内能追上他呢?
在这里插入图片描述
已知一张地图(以二维矩阵的形式表示)以及佐助和鸣人的位置。地图上的每个位置都可以走到,只不过有些位置上有大蛇丸的手下,需要先打败大蛇丸的手下才能到这些位置。鸣人有一定数量的查克拉,每一个单位的查克拉可以打败一个大蛇丸的手下。假设鸣人可以往上下左右四个方向移动,每移动一个距离需要花费 1 个单位时间,打败大蛇丸的手下不需要时间。如果鸣人查克拉消耗完了,则只可以走到没有大蛇丸手下的位置,不可以再移动到有大蛇丸手下的位置。佐助在此期间不移动,大蛇丸的手下也不移动。请问,鸣人要追上佐助最少需要花费多少时间?

输入格式

输入的第一行包含三个整数:M,N,T。代表 M 行 N 列的地图和鸣人初始的查克拉数量 T。
0 < M,N < 200, 0≤T<10
后面是 M 行 N 列的地图,其中 @ 代表鸣人,+ 代表佐助。* 代表通路,# 代表大蛇丸的手下。

输出格式

输出包含一个整数 R,代表鸣人追上佐助最少需要花费的时间。如果鸣人无法追上佐助,则输出 -1。

输入样例1

4 4 1
#@##
**##
###+
****

输出样例1

6

输入样例2

4 4 2
#@##
**##
###+
****

输出样例2

4

题目分析

BFS的变种问题,加上了一个状态,所以以前的vis的普通二维的标记是过不了,因为不能判断当前是否为最佳路径,有可能一路杀过来会更快,所以用一个三维数组来标记当前坐标和当前的查克拉量来记录如果有z的查克拉来到x,y的位置有没有走过;

代码实现

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=205;
char a[maxn][maxn];
int vis[maxn][maxn][15]={0};
int n,m,ckl,sj;
int sx,sy,fx,fy;
int dir[4][2]={{0,-1},{1,0},{0,1},{-1,0}};
struct node
{
	int x,y;
	int t;
	int ckl;
	node(int x,int y,int s,int c):x(x),y(y),t(s),ckl(c){ }
};
queue<node> q;
bool pd(int x,int y)
{
	if(x>=1&&x<=m&&y>=1&&y<=n)
		return true;
	else
		return false;
}
void bfs(int x,int y,int ckl)
{
	vis[x][y][ckl]=1;
	q.push(node(x,y,0,ckl));
	while(!q.empty())
	{
		node now=q.front();
		q.pop();
		for(int i=0;i<4;i++)
		{
			int nx=now.x+dir[i][0];
			int ny=now.y+dir[i][1];
			if(pd(nx,ny)&&vis[nx][ny][now.ckl]==0)
			{
				if(nx==fx&&ny==fy)//所经过的时间都是1所以第一次到的一定是最短路径
				{
					sj=now.t+1;
					return;
				}
				if(a[nx][ny]=='#'&&now.ckl>0)//如果有敌人而且有查克拉就走
				{
					vis[nx][ny][now.ckl-1]=1;
					//在此剩余查克拉-1时标记经过了,下次就跳过,因为下次经过此点一定比这次经过的时间要长
					q.push(node(nx,ny,now.t+1,now.ckl-1));
				}
				if(a[nx][ny]=='*')
				{
					vis[nx][ny][now.ckl]=1;
					q.push(node(nx,ny,now.t+1,now.ckl));
				}
			}
		}
	}
}
int main()
{
	memset(vis,0,sizeof(vis));
	sj=99999;
	cin>>m>>n>>ckl;//m行n列
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>a[i][j];
			if(a[i][j]=='@')
			{
				sx=i;
				sy=j;
			}
			if(a[i][j]=='+')
			{
				fx=i;
				fy=j;	
			} 
		} 
	}
	bfs(sx,sy,ckl);
	if(sj==99999)
	{
		cout<<-1;
	}
	else
	{
		cout<<sj;
	}
}

最后再附上一个参考别人用二维数组剪枝来写的代码
别人的题解
此题需要特殊判重(判重的意义在于不再走重复的路,防止进入死循环),简单判重只用于到达某位置只是先后次序不同,其他状态相同。而此题由于先后到达某点的路径不同,查克拉的数量可能也会有所不同(甚至会影响是否能到达终点),因此不能简单的判重。
如果后面到达时的查克拉数量大于之前到达的量则可以加入队列(以免走了最前面的路消耗完查克拉最后到达不了终点)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=205;
char a[maxn][maxn];
int vis[maxn][maxn];
int n,m,ckl,sj;
int sx,sy,fx,fy;
int dir[4][2]={{0,-1},{1,0},{0,1},{-1,0}};
struct node
{
	int x,y;
	int t;
	int ckl;
	node(int x,int y,int s,int c):x(x),y(y),t(s),ckl(c){ }
};
queue<node> q;
void bfs(int x,int y,int ckl)
{
	vis[x][y]=ckl;
	q.push(node(x,y,0,ckl));
	while(!q.empty())
	{
		node now=q.front();
		q.pop();
		if(a[now.x][now.y]=='+')
		{
			sj=now.t;
			return;
		}
		for(int i=0;i<4;i++)
		{
			int nx=now.x+dir[i][0];
			int ny=now.y+dir[i][1];
			if(nx<1||nx>m||ny<1||ny>n)
				continue;
			if(a[nx][ny]=='#'&&vis[nx][ny]<=now.ckl)//现有查克拉数要大于之前位置的最大药量才能加入队列
			{
				vis[nx][ny]=now.ckl-1;
				q.push(node(nx,ny,now.t+1,now.ckl-1));
			}
			else if(a[nx][ny]!='#'&&vis[nx][ny]<now.ckl)
			{
				vis[nx][ny]=now.ckl;
				q.push(node(nx,ny,now.t+1,now.ckl));
			}
		}
	}
}

int main()
{
	sj=99999;
	cin>>m>>n>>ckl;
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>a[i][j];
			vis[i][j]=-1;
			if(a[i][j]=='@')
			{
				sx=i;
				sy=j;
			}
			if(a[i][j]=='+')
			{
				fx=i;
				fy=j;	
			} 
		} 
	}
	bfs(sx,sy,ckl);
	if(sj==99999)
	{
		cout<<-1;
	}
	else
	{
		cout<<sj;
	}
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是用C++实现的代码: ``` #include <iostream> #include <queue> #include <cstring> using namespace std; const int MAXN = 205; const int INF = 0x3f3f3f3f; char map[MAXN][MAXN]; int dis[MAXN][MAXN][15]; int dx[] = {-1, 0, 1, 0}; int dy[] = {0, 1, 0, -1}; struct Node { int x, y, chakra; }; int bfs(int sx, int sy, int ex, int ey, int t) { memset(dis, INF, sizeof(dis)); queue<Node> q; q.push({sx, sy, t}); dis[sx][sy][t] = 0; while (!q.empty()) { Node now = q.front(); q.pop(); if (now.x == ex && now.y == ey) { return dis[now.x][now.y][now.chakra]; } if (map[now.x][now.y] == '#') { continue; } for (int i = 0; i < 4; i++) { int nx = now.x + dx[i]; int ny = now.y + dy[i]; if (nx < 0 || nx >= MAXN || ny < 0 || ny >= MAXN) { continue; } if (map[nx][ny] == '#') { continue; } if (map[nx][ny] == '+' && now.chakra == 0) { continue; } int nxt_chakra = now.chakra; if (map[nx][ny] == '+') { nxt_chakra--; } if (dis[nx][ny][nxt_chakra] > dis[now.x][now.y][now.chakra] + 1) { dis[nx][ny][nxt_chakra] = dis[now.x][now.y][now.chakra] + 1; q.push({nx, ny, nxt_chakra}); } } } return -1; } int main() { int m, n, t; cin >> m >> n >> t; int sx, sy, ex, ey; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { cin >> map[i][j]; if (map[i][j] == '@') { sx = i; sy = j; } if (map[i][j] == '+') { ex = i; ey = j; } } } cout << bfs(sx, sy, ex, ey, t) << endl; return 0; } ``` 思路解析: 题目要求求出人跟之间的最短时间,因此可以使用 BFS 求解。 首先读入地图和人的初始查克拉数量 T,然后使用 BFS 从人的初始位置开始搜索。在 BFS 的过程中,需要记录人到每个点所需的最短时间,以及人在到达该点时所剩下的查克拉数量。如果人到某个点时查克拉数量为 0,那么就不能继续前进到有大蛇丸手下的位置了。 当人到达的位置时,就可以得到人追上所需要的最短时间。 需要注意的是,题目中给出的地图大小为 M×N,其中 M 和 N 都可能达到 200,因此需要开较大的数组来存储最短时间和人的查克拉数量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值