003:鸣人和佐助 程序设计实习MOOC / 程序设计与算法(二)第10周测验(2020春季)

描述

佐助被大蛇丸诱骗走了,鸣人在多少时间内能追上他呢?

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

输入

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

输出

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

样例输入

样例输入1
4 4 1
#@##
**##
###+
****

样例输入2
4 4 2
#@##
**##
###+
****

样例输出

样例输出1
6

样例输出2
4

解题思路

这题有点像走迷宫,只不过增加了查克拉这个限制因素。一般来说深搜跑一下就能解决这个问题。但是这题考察的是剪枝,如果不剪枝的话,交上去会超时。所以我们要想办法剪枝。有两种常用的剪枝办法。

  1. 可行性剪枝
  2. 最优性剪枝

我用的是最优行剪枝,用一个 mid[i][j][k] 记录走到 ( i , j ) 这个位置时查克拉为k所用的最短时间,如果下一次以相同的情况走到这个位置来,发现所用的时间比我记录下来的最短时间要长,那么这个肯定不是我们要的答案,就放弃这条路,寻找下一条。如果发现所用的时间比我们记录的最短时间还要短那么就把最短时间更新,以便下一次的比较。 

AC Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<vector>
#include<list>
#include<stack>
#include<queue>
//#include<map>
#include<set>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

typedef long long ll;
const double PI = acos(-1);
const double EPS = 1e-6;
const int INF = 0x3f3f3f3f;
const int MAXN = 200 + 10;
char map[MAXN][MAXN];
bool visited[MAXN][MAXN];
int mid[MAXN][MAXN][11];//time[i][j][k] 代表走到x y时有k个查克的最短时间
int m, n, t, sx, sy, minTime=INF, times;

void dfs(int x, int y, int t){
	if(map[x][y]=='+') {
		minTime=min(minTime, times);
		return ;
	}
	else if(visited[x][y] || x<0 || x>m-1 || y<0 || y>n-1) return ;
	else if(!visited[x][y] && map[x][y]=='#' && t>0){
		if(times+1>=minTime) return;
		if(times+1>=mid[x][y][t]) return;
		++times;
		mid[x][y][t] = times;
		visited[x][y]=1;
		dfs(x-1,y,t-1);
		dfs(x+1,y,t-1);
		dfs(x,y-1,t-1);
		dfs(x,y+1,t-1);
		visited[x][y]=0;
		--times;
	} else if (!visited[x][y] && map[x][y]=='*' || map[x][y]=='@') {
		if(times+1>=minTime) return;
		if(times+1>=mid[x][y][t]) return;
		++times;
		mid[x][y][t] = times;
		visited[x][y]=1;
		dfs(x-1,y,t);
		dfs(x+1,y,t);
		dfs(x,y-1,t);
		dfs(x,y+1,t);
		visited[x][y]=0;
		--times;
	}
	return ;
}
int main(){
    freopen("C:\\Users\\Ambition\\Desktop\\in.txt","r",stdin);
	while(~scanf("%d %d %d", &m, &n, &t)){
		memset(visited,0,sizeof(visited));
		memset(mid,INF,sizeof(mid));
		for(int i=0; i<m; ++i){
			scanf("%s",map[i]);
			char *p=strchr(map[i],'@');
			if(p){
				sx=i;
				sy=p-map[i];
			}
		}
		//printf("%d %d\n",sx, sy);
		dfs(sx, sy, t);
		if(minTime!=INF)
			printf("%d\n", minTime);
		else
			printf("-1\n");
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值