小项目:迷宫二

引言

这个迷宫项目是今天参加学校的一个比赛出的题目,从早上九点基本搞到了四五点才完成,其实写出来发现基本思路其实挺简单的,就是想不好想,真的要各种的尝试,也训练反应和一个执行力,不过也算挺好的,现在给出题目。

一、题目描述

题目描述:
勇敢的盖伦前往诺克萨斯的地牢去解救美丽的光辉女神拉克丝,但是诺克萨斯的地牢机关重重、危机四
伏,请你帮助盖伦解救拉克丝。
诺克萨斯的地牢是一个14×14 的矩阵,该矩阵由如下几种元素组成:道路、墙壁、炸弹、传送门、怪物
组成,如下图所示:

在这里插入图片描述

解题规则
(1)盖伦拥有初始值为100的生命值,初始位置在矩阵中第2行第1列;拉克丝被关押的位置在矩阵中
第12行第13列;盖伦到达拉克丝所在的格子,则视为解救成功;
(2)白色格子为道路,盖伦可以到达;盖伦只能朝正北、正南、正东、正西这四个方向移动,每次只
能移动一格;
(3)褐色格子为墙壁,盖伦不可到达;
(4)炸弹放置在道路上,当盖伦到达该格子时则引发爆炸,盖伦自身扣除10生命值,同时炸弹将周边
(8个格子)存在的墙壁炸开变为道路,如周边存在怪物也一同炸消失;
(5)地牢中有10只小怪和3只大龙放置在道路上;当盖伦到达小怪格子,盖伦自身扣除5生命值,同时
该小怪消失;当盖伦到达大龙格子,盖伦自身扣除20生命值,同时该大龙消失;
(6)地牢中有3组传送门放置在道路上,其中A-B一组、C-D一组、E-F一组;当盖伦从别的非传送门格
子到达传送门A格子时,立即位移到传送门B格子,反之亦然;C-D传送门,E-F传送门同理。
问题求解
(1)盖伦是否能在存活的情况下,解救拉克丝?
(2)哪种解救方案(盖伦移动的路径)可以让盖伦扣除最少的生命值?
(3)自行设计一个 20×20 的地牢,其中至少包含12个炸弹、15只小怪、6只大龙、6组传送门;墙壁
的个数至少是所有格子的一半;盖伦初始位置在第1行第1列,拉克丝被关押的位置在第20行第20列;
同时求解上述两个问题;

二、解题思路

就是不断地dfs然后递归到终点,否则回退,再递归,再到终点的话就更新。
说一下自己的思路历程:一说这个最短路的话,首先肯定是想到要用bfs做的,可是这个你第一次就到终点的方案也不一定是最优的啊,这个规则是你最终到达终点的血量最多才是最优的,所以说这个规则就不太能适用了,而且有炸弹这个东西,你肯定不能只有一个地图啊,而且你把一个走过炸弹的结点加入队列中,你怎么判断你从队列取出的结点该用哪一张地图,这就很麻烦的。所以只能想到用dfs去不断地递归和回退,不过幸好自己有一个剪枝,这样就可以把绝大部分地分叉全部舍弃了,运行时间也是很短的,秒出答案。

三、代码实现

#if 1

#include <iostream>
#include <vector>
#include <unordered_map>
#include <cstring>
using namespace std;

const int N = 14;
const int MAZE_SIZE = 14;

//0为通路 1为墙壁 2为炸弹 3为大怪兽 4为小怪兽 6为传送门 8为终点
int maze[N][N] = {
	{1,1,1,1,1,1,1,1,1,1,1,1,1,1},  //0
	{0,0,0,0,0,0,1,1,1,0,0,0,0,1},  //1
	{1,0,1,2,1,0,4,0,2,1,1,1,2,1},  //2
	{1,0,1,4,1,1,1,1,1,1,0,4,0,1},  //3
	{1,0,1,6,1,0,6,0,1,0,0,1,1,1},  //4
	{1,0,1,1,1,3,0,0,1,0,4,1,3,1},  //5
	{1,4,0,0,1,1,1,1,1,6,0,1,6,1},  //6
	{1,0,1,0,1,0,0,4,0,0,0,1,0,1},  //7
	{1,0,1,0,4,2,1,1,1,1,4,1,1,1},  //8
	{1,2,0,6,1,0,0,0,1,1,0,2,0,1},  //9
	{1,1,1,1,1,1,1,0,0,1,0,1,1,1},  //10
	{1,0,0,3,0,0,1,4,2,1,0,1,8,1},  //11
	{1,0,4,1,0,6,1,0,0,1,0,0,0,1},  //12
	{1,1,1,1,1,1,1,1,1,1,1,1,1,1}   //13
};



int traverse[N];
vector<pair<int, int>> res;
vector<pair<int, int>> step;
int dir[4][2] = { 0,1,1,0,-1,0,0,-1 };
bool used[N][N];  

int hp_res = -1;

int get1(int x, int y)
{
	return x * 14 + y;
}

pair<int, int> get2(int n)
{
	pair<int, int> res;
	res.first = n / 14;
	res.second = n % 14;
	return res;
}

void init()
{
	//传送门
	//a[9,3] b[12,5] c[4,3] d[5,6] e[6,9] f[6,12]
	traverse[get1(9, 3)] = (get1(12, 5));
	traverse[get1(12, 5)] = (get1(9, 3));
	traverse[get1(4, 3)] = (get1(4, 6));
	traverse[get1(4, 6)] = (get1(4, 3));
	traverse[get1(6, 9)] = (get1(6, 12));
	traverse[get1(6, 12)] = (get1(6, 9));

	used[1][0] = true;
	step.push_back({ 1,0 });
}

void bomb(int x, int y)
{
	int dir[9][2] = { -1,-1,-1,0,-1,1,0,-1,0,0,0,1,1,-1,1,0,1,1 };
	for (int i = 0; i < 9; ++i)
	{
		int nx = x + dir[i][0];
		int ny = y + dir[i][1];

		if (nx < 0 || nx >= MAZE_SIZE || ny < 0 || ny >= MAZE_SIZE) continue;

		maze[nx][ny] = 0;
	}
}

void dfs(int startx, int starty, int cur_hp)
{
	if (cur_hp < 0) return;
	if (hp_res != -1 && cur_hp < hp_res) return;

	for (int i = 0; i < 4; ++i)
	{
		int nx = startx + dir[i][0];
		int ny = starty + dir[i][1];

		if (nx < 0 || nx >= MAZE_SIZE || ny < 0 || ny >= MAZE_SIZE) continue;
		if (used[nx][ny] || maze[nx][ny] == 1) continue;

		if (maze[nx][ny] == 0)  //通路
		{
			used[nx][ny] = true;
			step.push_back({ nx,ny });

			dfs(nx, ny,cur_hp);

			used[nx][ny] = false;
			step.pop_back();
		}
		else if (maze[nx][ny] == 2)  //炸弹
		{
			used[nx][ny] = true;
			int backup[N][N] = {0};
			memcpy(backup, maze, sizeof maze);
			bomb(nx, ny);
			step.push_back({ nx,ny });

			dfs(nx, ny,cur_hp-10);

			used[nx][ny] = false;
			step.pop_back();
			memcpy(maze, backup, sizeof maze);
		}
		else if (maze[nx][ny] == 3)  //大怪兽
		{
			used[nx][ny] = true;
			maze[nx][ny] = 0;
			step.push_back({ nx,ny });

			dfs(nx, ny,cur_hp - 20);

			used[nx][ny] = false;
			step.pop_back();
			maze[nx][ny] = 3;
		}
		else if (maze[nx][ny] == 4)  //小怪兽
		{
			used[nx][ny] = true;
			maze[nx][ny] = 0;
			step.push_back({ nx,ny });

			dfs(nx, ny,cur_hp-5);

			used[nx][ny] = false;
			step.pop_back();
			maze[nx][ny] = 4;
		}
		else if (maze[nx][ny] == 6)  //传送门
		{
			used[nx][ny] = true;
			int t = get1(nx, ny);
			pair<int, int> next = get2(traverse[t]);
			step.push_back({ nx,ny });
			step.push_back({ next.first,next.second });

			dfs(next.first, next.second,cur_hp);

			used[nx][ny] = false;
			step.pop_back();
			step.pop_back();
		}
		else if(maze[nx][ny] == 8)  //终点
		{
			step.push_back({ nx,ny });
			if (cur_hp > hp_res)
			{
				hp_res = cur_hp;
				res = step;
			}
			step.pop_back();

			return;
		}

		
		
	}
}

int main()
{
	init();
	dfs(1, 0,100);
	if (hp_res <= 0)
	{
		cout << "false" << endl;
	}
	else
	{
		cout << "true" << endl;
		cout << hp_res << endl;
		int cnt = 1;
		for (int i = 0; i < res.size(); ++i)
		{
			printf("(%02d,%02d)", res[i].first, res[i].second);
			if (cnt % 10 == 0) puts("");
			else if(i != res.size() - 1) printf("->");
			cnt++;
		}
	}
	
	return 0;
}

#endif

四、测试

在这里插入图片描述

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lijiachang030718

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值