2020安徽省大学生程序设计大赛题解——J 飞奔的战士

2020安徽省大学生程序设计大赛题解——J 飞奔的战士

J 飞奔的战士

题目

众所周知, T e u t o n i c K n i g h t Teutonic Knight TeutonicKnight 是某 R T S RTS RTS 游戏中,移动速度最快的单位。而且他热衷于参加赛跑比赛。现在他想知道他最快需要用多长时间才可以到达终点,假设他没有开加速挂。起初,他站在第 1 1 1 张图的某个位置(用 S S S标识),终点在第 k k k 张图的某个位置(用 E E E标识),在除最后一张图外,每一张图上有且仅有一个传送点(用 T T T标识),可以将他传送到下一张图的某个位置,用 t t t标识。传送不需要任何时间,可以理解为瞬间完成。每次移动一个单位距离耗时 1 1 1 秒。现在 T e u t o n i c K n i g h t Teutonic Knight TeutonicKnight 想知道他在全程狂奔的情况下,最快需要多长时间才能到达终点。

在这里插入图片描述

标签

数组,队列,图的BFS,迷宫问题

分析

这道题是一道迷宫求最短路径问题。直接思路是图的 B F S BFS BFS算法,设置一个 d [ i ] [ j ] d[i][j] d[i][j]的二维数组来存储从起点到坐标 ( i , j ) (i,j) (i,j)的最短距离,但与一般的迷宫问题所不同的是该题涉及多个迷宫,依次进行 n n n B F S BFS BFS,最后将 n n n次的时间累加起来。

首先从题目的条件入手,题目要求输出最快能够发现一个圣物的秒数,每秒向上下左右四个方向各移动一个单位,因此问题转化为求从起点到达其中一个圣物的最短路径问题。

用数组 c h a r   g [ k ] [ i ] [ j ] ; char \ g[k][i][j]; char g[k][i][j];存储用户输入的迷宫符号,表示第 k k k张图的第 ( i , j ) (i,j) (i,j)个位置,
一行一行的读入每张迷宫地图的各状态,然后从起点开始 B F S BFS BFS算法。

然后是 B F S BFS BFS算法:
找到从起点到终点的最短路径其实就是一个建立队列的过程:
1.从起点开始,将其加入队列,设置距离为 0 0 0;
2.从队列首端取出位置,将从这个位置能够到达的位置加入队列,并且让这些位置的距离为上一个位置的距离加上 1 1 1;
3.一轮探索至无法继续向队列中添加元素,即当前所在点的四周情况全部考虑完成后,循环第二步,直到将传送点 T T T/终点添加到队列中。说明此时已经找到了最短路径;

完整的 B F S BFS BFS代码如下:

int bfs(int p, int sx, int sy) { //从人当前开始广度优先搜索遍历
    memset(d, -1, sizeof(d));
    queue<Node> Q;
    Q.push({ sx,sy }); //放入第一个人的当前状态入队
    d[sx][sy] = 0;
    while (!Q.empty()) {
        auto t = Q.front();
        Q.pop();
        int x = t.x, y = t.y;
        int dd = d[x][y];
        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i], ny = y + dy[i];
            if (!vaild(nx, ny)) continue;
            if (g[p][nx][ny] == '#') continue;
            if (g[p][nx][ny] == 'E' || g[p][nx][ny] == 'T') return dd + 1;
            if (g[p][nx][ny] == '.') {
                if (d[nx][ny] != -1) continue;
                d[nx][ny] = dd + 1;
                Q.push({ nx,ny });
            }
        }
    }
    return -1;
}

最后,将每张地图搜索到的 B F S BFS BFS路径相加,即为总的最短路径
(若有一张图走不通就输出 " T r a p p e d M a z e ! ! ! " "Trapped Maze!!!" "TrappedMaze!!!"

参考答案(C++)
#include<bits/stdc++.h>
using namespace std;
const int N = 30;
const int dx[] = { 1,-1,0,0 }, dy[] = { 0,0,1,-1 };                    //人行进的方向
int k, n, m;
char g[100][100][100];                                                 //迷宫
int d[100][100];                                                       //到当前状态的最小距离
bool vaild(int x, int y) { return x > 0 && x <= n && y > 0 && y <= m; }//判断是否在迷宫中
bool flag = true;
struct Node {             //记录当前的状态
    int  x, y; //x,y表示当前的位置 id表示当前是第几张图
    Node() {}
    Node(int x, int y) : x(x), y(y) {}
};

int bfs(int p, int sx, int sy) { //从人当前开始广度优先搜索遍历
    memset(d, -1, sizeof(d));
    queue<Node> Q;
    Q.push({ sx,sy }); //放入第一个人的当前状态入队
    d[sx][sy] = 0;
    while (!Q.empty()) {
        auto t = Q.front();
        Q.pop();
        int x = t.x, y = t.y;
        int dd = d[x][y];
        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i], ny = y + dy[i];
            if (!vaild(nx, ny)) continue;
            if (g[p][nx][ny] == '#') continue;
            if (g[p][nx][ny] == 'E' || g[p][nx][ny] == 'T') return dd + 1;
            if (g[p][nx][ny] == '.') {
                if (d[nx][ny] != -1) continue;
                d[nx][ny] = dd + 1;
                Q.push({ nx,ny });
            }
        }
    }
    return -1;
}
int main() {
    cin >> k >> n >> m;                          //输入迷宫的个数与行列
    for (int p = 1; p <= k; p++)
        for (int i = 1; i <= n; i++)
            cin >> g[p][i] + 1;                  //输入迷宫各状态,由于数据是一行一行的给的,故
    int sx = 0, sy = 0, path = 0;
    for (int p = 1; p <= k; p++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (g[p][i][j] == 'S' || g[p][i][j] == 't') {
                    sx = i, sy = j;    //标记人
                    int ans = bfs(p, sx, sy);
                    if (ans == -1) {
                        flag = false;
                        cout << "Trapped Maze!!!";
                    }
                    else path += ans;
                }
            }
        }
    }
    if(flag)
        cout << path << endl;
    return 0;
}
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值