OJ 4105 拯救公主__广搜

2024-04-20 17:18
文章标签 公主 拯救 oj 4105

本文主要是介绍OJ 4105 拯救公主__广搜,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

描述

多灾多难的公主又被大魔王抓走啦!国王派遣了第一勇士阿福去拯救她。
身为超级厉害的术士,同时也是阿福的好伙伴,你决定祝他一臂之力。你为阿福提供了一张大魔王根据地的地图,上面标记了阿福和公主所在的位置,以及一些不能够踏入的禁区。你还贴心地为阿福制造了一些传送门,通过一个传送门可以瞬间转移到任意一个传送门,当然阿福也可以选择不通过传送门瞬移。传送门的位置也被标记在了地图上。此外,你还查探到公主所在的地方被设下了结界,需要集齐K种宝石才能打开。当然,你在地图上也标记出了不同宝石所在的位置。
你希望阿福能够带着公主早日凯旋。于是在阿福出发之前,你还需要为阿福计算出他最快救出公主的时间。
地图用一个R×C的字符矩阵来表示。字符S表示阿福所在的位置,字符E表示公主所在的位置,字符#表示不能踏入的禁区,字符$表示传送门,字符.表示该位置安全,数字字符0至4表示了宝石的类型。阿福每次可以从当前的位置走到他上下左右四个方向上的任意一个位置,但不能走出地图边界。阿福每走一步需要花费1个单位时间,从一个传送门到达另一个传送门不需要花费时间。当阿福走到宝石所在的位置时,就视为得到了该宝石,不需要花费额外时间。

输入

第一行是一个正整数T(1 <= T <= 10),表示一共有T组数据。
每一组数据的第一行包含了三个用空格分开的正整数R、C(2 <= R, C <= 200)和K,表示地图是一个R×C的矩阵,而阿福需要集齐K种宝石才能够打开拘禁公主的结界。
接下来的R行描述了地图的具体内容,每一行包含了C个字符。字符含义如题目描述中所述。保证有且仅有一个S和E。$的数量不超过10个。宝石的类型在数字0至4范围内,即不会超过5种宝石。

输出

对于每一组数据,输出阿福救出公主所花费的最少单位时间。若阿福无法救出公主,则输出“oop!”(只输出引号里面的内容,不输出引号)。每组数据的输出结果占一行。

样例输入

1
7 8 2
……..
..S..#0.
.##..1..
.0#…..
…1#…
…##E..
…1….

样例输出

11

分析

迷宫问题,区别在于要集齐宝石,并且有传递门,因为有宝石数目限制所以是否访问过的标记要增加一个维度用户表示特定宝石数目下是否访问过某一结点。这次7218变的写法是用常规的(x,y)表示坐标了,确认这样更好写些。。
郁闷的是写出来后样例通过了,也自己找了很多测试项通过了,结果提示OJ死活过不了,之后睡了一觉隔了一天才想到是doorCount没有置0!吐血三升!!!

实现

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
using namespace std;
#define MAX 201
char a[MAX][MAX];struct Node
{int x, y; //坐标。int gem = 0; //存储宝石数目。int deep = 0; //搜索深度。Node() {}Node(int xx, int yy, int gg, int dd) : x(xx), y(yy), gem(gg), deep(dd) {}
};int dir[4][2] = {{0, -1},{-1, 0},{0, 1},{1, 0}};
int visited[MAX][MAX][1 << 5 - 1];   //宝石数目最大11111
int r, c, k, doorCount;
Node doors[11];void print(int result) {result == -1 ? (cout << "oop!" << endl) : (cout << result << endl);
}int bit1Count(int value) {unsigned int count = 0;while (value > 0) { // until all bits are zeroif ((value & 1) == 1) // check lower bitcount++;value >>= 1; // shift bits, removing lower bit}return count;
}void printQueue(std::queue<Node> q) {while (!q.empty()) {Node node = q.front();q.pop();cout << "(" << node.x << ", " << node.y << ", "<< bit1Count(node.gem) << ", " << node.deep << ") ";}cout << endl << endl;
}int getTarget(Node* node, Node* endNode) {return (node->x == endNode->x && node->y == endNode->y && bit1Count(node->gem) >= k);
}int bfs(Node* startNode, Node* endNode) {if (startNode == NULL || endNode == NULL) return -1;memset(visited, 0, sizeof(visited));visited[startNode->x][startNode->y][0] = 1;std::queue<Node> q;q.push(*startNode);while (!q.empty()) {Node node = q.front();q.pop();for (int i = 0; i < 4; i++) {int newX = node.x + dir[i][0];int newY = node.y + dir[i][1];if (newX < 0 || newX >= r || newY < 0 || newY >= c) continue;if (a[newX][newY] == '#' || visited[newX][newY][node.gem]) continue;//不是墙壁并且此节点没访问过。visited[newX][newY][node.gem] = 1;//记录宝石数量。Node newNode(newX, newY, node.gem, node.deep + 1);if (a[newX][newY] >= '0' && a[newX][newY] <= '4') {newNode.gem |= 1 << (a[newX][newY] - '0');}if (getTarget(&newNode, endNode)) {//printQueue(q);return newNode.deep;}q.push(newNode);//如果是传送门的话就将所有其它传送门加入搜索队列。if (a[newX][newY] == '$') {for (int j = 0; j < doorCount; j++) {Node currNode = doors[j];if (currNode.x == newX && currNode.y == newY) continue;Node doorNode(currNode.x, currNode.y, newNode.gem, newNode.deep);q.push(doorNode);}}}//printQueue(q);}return -1;
}int main() {//  freopen("in.txt", "r", stdin);int t;cin >> t;while (t--) {Node *startNode = NULL, *endNode = NULL;cin >> r >> c >> k;doorCount = 0;for (int i = 0; i < r; i++) {for (int j = 0; j < c; j++) {cin >> a[i][j];//记录所有传送门的位置。switch (a[i][j]) {case '$':doors[doorCount++] = Node(i, j, 0, 0);break;case 'S':startNode = new Node(i, j, 0, 0);break;case 'E':endNode = new Node(i, j, 0, 0);}}}print(bfs(startNode, endNode));}return 0;
}

这篇关于OJ 4105 拯救公主__广搜的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/920863

相关文章

哈理工OJ 2179(深搜)

组合 Time Limit: 1000 MSMemory Limit: 32768 K Total Submit: 7(5 users)Total Accepted: 6(5 users)Rating: Special Judge: No Description 给出一个正整数N,从集合{1,2,3..N} 中找出所有大小为k的子集, 并按照字典序从小到大输出。 Input 第一行是一个整

每日OJ_牛客_求和(递归深搜)

目录 牛客_求和(递归深搜) 解析代码 牛客_求和(递归深搜) 求和_好未来笔试题_牛客网 解析代码         递归中每次累加一个新的数,如果累加和大于等于目标,结束递归。此时如果累加和正好等于目标,则打印组合。向上回退搜索其它组合。此题本身就是一个搜索的过程,找到所有的组合。 #include <iostream>#include <cmath>#in

OJ-0905

题目 示例1: 输入:10 10 56 34 99 1 87 8 99 3 255 6 99 5 255 4 99 7 255 2 99 9 255 213 4输出:99 示例2: 输入:10 10 255 34 0 1 255 8 0 3 255 6 0 5 255 4 0 7 255 2 0 9 255 213 5输出:255 import java.util.

U盘未初始化困境与数据拯救

U盘未初始化现象深度剖析 在数字化时代,U盘作为便携式存储设备,承载着人们日常学习、工作、生活中的大量数据。然而,当U盘突然显示“未初始化”时,这些宝贵的数据仿佛一夜之间被锁进了无形的牢笼,让人心急如焚。U盘未初始化,意味着其文件系统结构可能已遭破坏,导致操作系统无法正确识别并访问其中的数据。这一现象背后,可能隐藏着多种原因:文件系统损坏、分区表丢失、不当的插拔操作、甚至是物理层面的轻微损伤等。

每日OJ_牛客_Emacs计算器(逆波兰表达式)

目录 牛客_Emacs计算器(逆波兰表达式) 解析代码 牛客_Emacs计算器(逆波兰表达式) Emacs计算器__牛客网 解析代码 逆波兰表达式(后缀表达式)求值,需要借助栈,思路: 循环输入,获取逆波兰表达式,然后进行以下补助,直到测试完所有的测试用例: 遇到数字字符串,将该数字字符串转化为数字然后入栈。遇到操作符时,从栈顶取两个数字,然后进行该运算符所对应运算

西北工业大学oj题-兔子生崽

题目描述: 兔子生崽问题。假设一对小兔的成熟期是一个月,即一个月可长成成兔,每对成兔每个月可以生一对小兔,一对新生的小兔从第二个月起就开始生兔子,试问从一对兔子开始繁殖,一年以后可有多少对兔子? 这道题目一眼看过去就是典型的递归问题,代码如下 public class RabbitReproduction {public static void main(String[] args) {in

★ 算法OJ题 ★ 力扣209 - 长度最小的子数组

Ciallo~(∠・ω< )⌒☆ ~ 今天,简将和大家一起做一道滑动窗口算法题--长度最小的子数组~ 目录 一  题目 二  算法解析 解法⼀:暴力求解 解法二:滑动窗口 三  编写算法 一  题目 209. 长度最小的子数组 - 力扣(LeetCode) 二  算法解析 解法⼀:暴力求解 算法思路: 从前往后枚举数组中的任意⼀个元素,把它当成起始位置

OJ-0903

题目 示例1 输入:30 12 25 8 19输出:15 示例2 输入:10 12 25 8 19 8 6 4 17 19 20 30输出:-1 题解 import java.util.ArrayList;import java.util.List;import java.util.Scanner;public class Main {public static

【负载均衡式在线OJ】Compile_server 模块

文章目录 程序源码compile_server整体思路编译(compile.hpp)运行模块编译运行模块编译运行服务 程序源码 https://gitee.com/not-a-stupid-child/online-judge compile_server 整体思路 这个服务要对oj_server 发送过来的代码进行编译和运行,最后把结果返回给oj_server。 所以我

★ 算法OJ题 ★ 力扣18 - 四数之和

Ciallo~(∠・ω< )⌒☆ ~ 今天,爱丽速子将和大家一起做一道双指针算法题--四数之和~ 目录 一  题目 二  算法解析 三  编写算法  做此题前最好先看一下前两篇博客~: ★ 算法OJ题 ★ 力扣 LCR179 - 和为 s 的两个数字-CSDN博客 ★ 算法OJ题 ★ 力扣15 - 三数之和-CSDN博客 一  题目 18. 四数之和 - 力扣(Lee