地下迷宫
题目描述
小青蛙有一天不小心落入了一个地下迷宫,小青蛙希望用自己仅剩的体力值P跳出这个地下迷宫。
为了让问题简单,假设这是一个n*m
的格子迷宫,迷宫每个位置为0
或者1
,
0
代表这个位置有障碍物,小青蛙达到不了这个位置;
1
代表小青蛙可以达到的位置。
小青蛙初始在(0,0
)位置,地下迷宫的出口在(0,m-1
)(保证这两个位置都是1
,并且保证一定有起点到终点可达的路径),小青蛙在迷宫中水平移动一个单位距离需要消耗1
点体力值,向上爬一个单位距离需要消耗3
个单位的体力值,向下移动不消耗体力值,当小青蛙的体力值等于0的时候还没有到达出口,小青蛙将无法逃离迷宫。现在需要你帮助小青蛙计算出能否用仅剩的体力值跳出迷宫(即达到(0,m-1
)位置)。
输入描述
输入包括n+1
行:
第一行为三个整数n,m
(
3
≤
m
,
n
≤
10
3 \leq m,n \leq 10
3≤m,n≤10 ),P
(
1
≤
P
≤
100
1 \leq P \leq 100
1≤P≤100 )
接下来的n
行:
每行m
个0
或者1
,以空格分隔
输出描述
如果能逃离迷宫,则输出一行体力消耗最小的路径,输出格式见样例所示;
如果不能逃离迷宫,则输出Can not escape!
。 测试数据保证答案唯一
示例一
输入
4 4 10
1
0
0
1
1
1
0
1
0
1
1
1
0
0
1
1
输出
[0,0],[1,0],[1,1],[2,1],[2,2],[2,3],[1,3],[0,3]
说明
参考解题 C
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include <assert.h>
//顶一个 迷宫 当前位置的坐标!(x,y)
typedef struct pos//精髓结构体
{
int x;
int y;
}pos;
typedef pos STDataType;//栈的data为pos坐标结构体
typedef struct Stack
{
STDataType* a;
int top; // 栈顶
int capacity; // 容量
}Stack;
Stack ans;//找到通路 回溯递归返回的时候 用个栈记下来,再输出 则就是0,0到终点的所有坐标;
//放全局好操作!
Stack tmpans;
void ChickStack(Stack* ps)
{
if (ps->capacity == ps->top)
{
Stack* tmp = (STDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(STDataType));
assert(tmp);
ps->a = tmp;
ps->capacity *= 2;
}
}
void StackInit(Stack* ps)
{
ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);
ps->capacity = 4;
ps->top = 0;
}
// 入栈
void StackPush(Stack* ps, STDataType data)
{
assert(ps);
ChickStack(ps);
ps->a[ps->top] = data;
ps->top++;
}
// 支持动态增长的栈
// 出栈
void StackPop(Stack* ps)
{
assert(ps);
if (ps->top > 0) ps->top--;
}
// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
assert(ps);
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
int StackSize(Stack* ps)
{
assert(ps);
return ps->top;
}
int StackEmpty(Stack* ps)//1 真 0 假
{
assert(ps);
return ps->top == 0;
}
void StackDestroy(Stack* ps)
{
assert(ps);
ps->top = 0;
free(ps->a);
ps->a = NULL;
ps->capacity = 0;
}
bool Ispass(int** maze, int m, int n, int p, pos next)//判断next这个位置 能不能走!0能,1(墙)or 2(走过的位置)不能
{
if (next.x >= 0 && next.x < m
&& next.y >= 0 && next.y < n //还得满足 x,y横纵坐标不能越界啊,maze是个二维数组,注意边界
&& maze[next.x][next.y] == 1
&&p>=0) //不光满足该位置0没走过也不是墙
return true;
return false;
}
void Anscpy(Stack* a, Stack* b)
{
//b往a倒
a->a = (STDataType*)malloc(sizeof(STDataType) * b->capacity);
memcpy(a->a, b->a, sizeof(STDataType) * b->top);
a->capacity = b->capacity;
a->top = b->top;
}
//这个cur 不管是往下递归还是网上回溯都起到核心作用
void Find(int** maze, int m, int n, int p, pos cur)//回溯递归的 函数!! (默认上下左右回溯)
{ //像 图的遍历查找!像二叉树左右子树递归!像思路递归!
//临时记录下一位置 成了往下递归 不成 就四个方向换方向 继续找路!cur到时候确认了要压栈,不能变呀!
//注意!!!!pos要选上下左右走,所以是cur的拷贝 成了就是下一递归的cur 不成就继续next = cur 再继续!
maze[cur.x][cur.y] = 2;
StackPush(&ans, cur);//先押入 不得行最后false之前再弹出
//既然递归 那就得有结束条件啊!! 找到了(直接层层沿轨迹弹出并记录) or (false,换四路递归的其他路).
//规定出口右下角那个点。
if (cur.x == 0 && cur.y == n - 1) //如果这个if里成立 就是到了终点,则路线的Find递归也会依次全部返回true
{
//终点
if (p >= 0 && StackEmpty(&tmpans)
|| StackSize(&ans) < StackSize(&tmpans))
{
Anscpy(&tmpans, &ans);//要深度拷贝 ans倒入tmpans
}
}
//上
pos next = cur;
next.x--;
if (Ispass(maze, m, n, p, next))
{
//next可以往下走 标记 再 递归下去!
Find(maze, m, n, p, next);
}
//上不行 就 下
next = cur;
next.x++;
if (Ispass(maze, m, n, p - 3, next))
{
//next可以往下走 标记 再 递归下去!
Find(maze, m, n, p - 3, next);
}
//下不行 就 左
next = cur;
next.y--;
if (Ispass(maze, m, n, p - 1, next))
{
//next可以往下走 标记 再 递归下去!
Find(maze, m, n, p - 1, next);
}
//左不行 就 右
next = cur;
next.y++;
if (Ispass(maze, m, n, p - 1, next))
{
//next可以往下走 标记 再 递归下去!
Find(maze, m, n, p - 1, next);
//恢复现场,设为未走!寻找最优解
}
//呜呜呜上下左右思路递归都没有找到目标,就false 换上层的下或左或右,知道第一层find的哲理,那就找不到啦
StackPop(&ans);
maze[cur.x][cur.y] = 1; //恢复现场,设为未走!寻找最优解
}
void Print(Stack* ans)//格式化倒输出答案
{
Stack tmp;
StackInit(&tmp);
while (!StackEmpty(ans))
{
StackPush(&tmp, StackTop(ans));
StackPop(ans);
}
while (StackSize(&tmp) > 1)
{
pos x = StackTop(&tmp);
printf("[%d,%d],", x.x, x.y);
StackPop(&tmp);
}
printf("[%d,%d]\n", tmp.a[0].x, tmp.a[0].y);//last one 格式不一样
StackPop(&tmp);
StackDestroy(&tmp);
}
int main()
{
//核心思路 体力值p先不管 求出所有路径 满足体力没完的!且!路径短的,更新ans就好!
int m, n, p;//m 行n 列
while (scanf("%d %d %d", &m, &n, &p) != EOF)
{
StackInit(&ans);
StackInit(&tmpans);
//创建迷宫:二维数组
int** maze = (int**)malloc(sizeof(int*) * m * n);
for (int i = 0; i < m; i++)
{
maze[i] = (int*)malloc(sizeof(int) * n);
}
//将数据scanf入迷宫
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
scanf("%d", &maze[i][j]);
}
}
pos cur = { 0,0 };//处时传入cur 当然是 起点 (0,0) //注意!!!!
Find(maze, m, n, p, cur);
if (!StackEmpty(&tmpans))
{
Print(&tmpans);
}
else
{
printf("Can not escape!\n");
}
//Find(maze,m,n,cur);//回溯迷宫过程;
//free掉当前迷宫!
for (int i = 0; i < m; i++)
{
free(maze[i]);
}
free(maze);
}
return 0;
}
参考解题 C++
#include <bits/stdc++.h>
using namespace std;
int dirx[] = {-1, 0, 1, 0};
int diry[] = {0, 1, 0, -1};
int value[] = {3, 1, 0, 1};
struct Node {
int x, y;
int p, pre;
Node(int x, int y, int p, int pre = -1) : x(x), y(y), p(p), pre(pre) {}
bool operator < (const Node &other) const {
return p > other.p;
}
};
int main()
{
int n, m, p;
while (cin >> n >> m >> p) {
vector<vector<int> > mp(n, vector<int>(m));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
int x;
cin >> x;
mp[i][j] = x;
}
}
deque<Node> que;
vector<vector<bool> > used(n, vector<bool>(m, false));
que.push_back(Node(0, 0, p));
int head = 0;
used[0][0] = true;
bool f = false;
int ans = 0;
while (!que.empty()) {
if (que.begin() + head == que.end())
break;
auto now = que[head++];
if (now.x == 0 && now.y == m - 1) {
f = true;
ans = head - 1;
break;
}
for (int i = 0; i < 4; i++) {
int tx = now.x + dirx[i], ty = now.y + diry[i];
int tp = now.p - value[i];
if (tx >= 0 && tx < n && ty >= 0 && ty < m && mp[tx][ty] == 1 && !used[tx][ty] && tp >= 0)
que.push_back(Node(tx, ty, tp, head - 1)), used[tx][ty] = true;
}
}
if (!f) {
cout << "Can not escape!" << endl;
} else {
stack<int> st;
while (que[ans].pre != -1)
st.push(que[ans].pre), ans = que[ans].pre;
while (!st.empty())
cout << "[" << que[st.top()].x << "," << que[st.top()].y << "],", st.pop();
cout << "[" << 0 << "," << m - 1 << "]" << endl;
}
}
return 0;
}
参考解题 Java
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] line = br.readLine().split(" ");
int n = Integer.parseInt(line[0]);
int m = Integer.parseInt(line[1]);
int p = Integer.parseInt(line[2]);
int[][] map = new int[n][m];
for (int i = 0; i < n; i++) {
line = br.readLine().split(" ");
for (int j = 0; j < m; j++) {
map[i][j] = Integer.parseInt(line[j]);
}
}
Solution s = new Solution(map);
System.out.println(s.solve(p));
}
}
class Solution {
int[][] map;
int[][] dirs = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int max = -1;
List<Integer> path = null;
boolean[][] visited;
Solution(int[][] map) {
this.map = map;
visited = new boolean[map.length][map[0].length];
}
public String solve(int p) {
dfs(new LinkedList<Integer>(), 0, 0, p);
if (max == -1) return "Can not escape!";
StringBuilder sb = new StringBuilder();
int i = 0, j = 0;
for (int d = 0; d < path.size(); d++) {
sb.append("[")
.append(i)
.append(",")
.append(j)
.append("]")
.append(",");
i += dirs[path.get(d)][0];
j += dirs[path.get(d)][1];
}
sb.append("[")
.append(i)
.append(",")
.append(j)
.append("]");
return sb.toString();
}
public void dfs(LinkedList<Integer> list, int i, int j, int p) {
if (i == 0 && j == map[0].length - 1 || p < 0) {
if (p > max) {
max = p;
path = new ArrayList<>(list);
}
return;
}
for (int d = 0; d < 4; d++) {
int x = i + dirs[d][0];
int y = j + dirs[d][1];
if (x >= 0 && x < map.length &&
y >= 0 && y < map[0].length &&
map[x][y] == 1 && !visited[x][y]) {
visited[x][y] = true;
list.addLast(d);
int q = p;
if (d == 0) q -= 3;
else if (d % 2 == 1) q -= 1;
dfs(list, x, y, q);
list.pollLast();
visited[x][y] = false;
}
}
}
}
参考解题 Python
n, m, P = list(map(int, input().split()))
maze = []
for i in range(n):
maze.append(list(map(int, input().split())))
def dfs(i, j, p, traj):
if i < 0 or j < 0 or i >= n or j >= m:
return False
if p < 0:
return False
if maze[i][j] == 0:
return False
if p == 0 and i != 0 and j != m-1:
return False
traj.append([i, j])
maze[i][j] = 0 # Mark the cell as visited
if p>= 0 and i==0 and j==m-1: # The Maze is finished
return True
return dfs(i, j+1, p-1, traj) or dfs(i-1, j, p-3, traj) or dfs(i+1, j, p, traj) or dfs(i, j-1, p-1, traj)
trajectory = []
if dfs(0, 0, P, trajectory):
res_str = ''
for t in trajectory:
res_str += '['+str(t[0])+','+str(t[1])+']'+','
print(res_str[:-1])
else:
print('Can not escape!')