CDOJ_149 解救小Q

本文介绍了一种使用广度优先搜索解决迷宫救援问题的方法。该算法考虑了迷宫中的陷阱、传送阵等因素,通过建立传送门对应关系并合理处理传送过程,实现了从起点到终点的最短路径计算。

原题网址:http://acm.uestc.edu.cn/#/problem/show/149

小Q被邪恶的大魔王困在了迷宫里,love8909决定去解救她。 迷宫里面有一些陷阱,一旦走到陷阱里,就会被困身亡:(,迷宫 里还有一些古老的传送

阵,一旦走到传送阵上,会强制被传送到 传送阵的另一头。

现在请你帮助love8909算一算,他至少需要走多少步才能解 救到小Q?

Input

第一行为一个整数T,表示测试数据组数。

每组测试数据第一行为两个整数NM,(1N,M50)表示 迷宫的长和宽。

接下来有N行,每行M个字符,是迷宫的具体描述。

  • .表示安全的位置
  • #表示陷阱,
  • Q表示小Q的位置
  • L表示love8909所在位置,

数据保证love8909只有一个,数据也保证小Q只有一个。

小写字母a-z表示分别表示不同的传送阵,数据保证传送阵 两两配对。

Output

每组数据输出一行,解救小Q所需的最少步数,如果无论如何都 无法救小Q,输出-1

Sample input and output

Sample Input Sample Output
2

5 5
....L
.###.
b#b#a
##.##
...Qa

5 5
....L
.###.
.#.#.
##.##
...Q.
3
-1
这道题采用广度优先搜索,每走过一个地方计算这个地方离起点的距离,并将这个点加入队列。不过要注意的是对应传送门的深度是相同的。为方便
处理,在输入的时候就将传送门的对应关系建立好。另外需要注意的是,在传送时,只能将传送门的一头标记为已访问,因为可能最短路是从另一头
传送过来的(传送门是双向的)。
好了,废话少说,献上代码。
#include<iostream>
#include<queue>
#include<string.h>
#define MAX_N 50
#define MAX_M 50
#define INF 3000
using namespace std;

typedef pair<int, int> P;
char maze[MAX_N + 5][MAX_M + 5];//迷宫
int d[MAX_N + 5][MAX_M + 5];//表示离起点的距离
int dx[4] = { 0, 1, 0, -1 };
int dy[4] = { 1, 0, -1, 0 };
P door[MAX_N + 5][MAX_M + 5];//储存传送门的对应关系
bool flag[MAX_N + 5][MAX_M + 5];//记录节点是否被访问过
int lx, ly, qx, qy;
int N, M;

void input()
{
    P temp[28];
    cin >> N >> M;
    fill(temp, temp + 28, P(INF, INF));
    for (int i = 0; i < N; i++)
        for (int j = 0; j < M; j++)
            door[i][j].first = door[i][j].second = INF;
    for (int i = 0; i < N; i++)
        for (int j = 0; j < M; j++)
        {
            char m;
            cin >> m;
            maze[i][j] = m;
            if (m >= 'a' && m <= 'z')
            {
                if (temp[m - 'a'] == P(INF, INF))//传送门第一次出现
                    temp[m - 'a'] = P(i, j);
                else//传送门已经出现过了
                {
                    door[i][j] = P(temp[m - 'a'].first, temp[m - 'a'].second);
                    door[temp[m - 'a'].first][temp[m - 'a'].second] = P(i, j);
                }
            }
            else if (m == 'L'){lx = i; ly = j; maze[i][j] = '#';}
            else if (m == 'Q'){ qx = i; qy = j; }
        }
}

int bfs()
{
    memset(flag, 0, sizeof(flag));
    for (int i = 0; i < N; i++)
        for (int j = 0; j < M; j++)
            d[i][j] = INF;
    queue<P> que;
    que.push(P(lx, ly));//将起点加入队列
    d[lx][ly] = 0;//并将起点的距离赋为0
    while (!que.empty())//不断循环,知道队列为空
    {
        int nx, ny;
        P now = que.front();//当前节点
        que.pop();
        if (now.first == qx&&now.second == qy)
            break;
        for (int i = 0; i < 4; i++)//向四个方向遍历
        {
            nx = now.first + dx[i];
            ny = now.second + dy[i];
            if (nx < N && nx >= 0 && ny < M && ny >= 0 && !flag[nx][ny])//未超边界,且未访问过
            {
                if (maze[nx][ny] <= 'z'&&maze[nx][ny] >= 'a')//传送门
                {
                    int dnow = d[now.first][now.second];
                    d[door[nx][ny].first][door[nx][ny].second] = dnow + 1;//传送
                    que.push(P(door[nx][ny].first, door[nx][ny].second));//将传送后的节点加入队列
                }
                else if (maze[nx][ny] != '#')//不是传送门
                {
                    d[nx][ny] = d[now.first][now.second] + 1;
                    que.push(P(nx, ny));
                }
                flag[nx][ny] = 1;//将节点标记为访问过
            }
        }
    }
    return d[qx][qy];
}

int main()
{
    int T;
    cin >> T;
    for (int t = 0; t < T; t++)
    {
        input();
        int res = bfs();
        cout << (res == INF ? -1 : res);
        if (t < T - 1)
            cout << endl;
    }
    return 0;
}



### CDOJ 300 木杆上的蚂蚁 #### 题目描述 题目涉及若干只蚂蚁在一个长度为 \( L \) 的水平木杆上移动。每只蚂蚁初始位置和方向已知,当两只蚂蚁相遇时会立即掉头反向行走。目标是计算所有蚂蚁终离开木杆的时间以及它们的顺序。 --- #### 解决方案概述 该问题的核心在于模拟蚂蚁的行为并处理碰撞事件。尽管表面上看起来需要复杂的碰撞检测逻辑,但实际上可以通过一种巧妙的方式简化问题:假设蚂蚁在碰撞时不改变方向,则可以忽略碰撞的影响[^2]。因此,只需关注每只蚂蚁到达木杆两端所需时间即可。 以下是解决问题的主要思路: 1. **输入解析** 输入数据包括测试用例数量 \( T \),每个测试用例包含木杆长度 \( L \) 和蚂蚁的数量 \( N \)。对于每只蚂蚁,记录其初始位置和移动方向(左或右)。 2. **时间和顺序计算** 对于每只蚂蚁: - 如果它朝左移动,则离木杆左侧的距离为其当前位置; - 如果它朝右移动,则离木杆右侧的距离为 \( L - \text{当前蚂蚁的位置} \)。 将这些距离存储下来,并按升序排列以确定蚂蚁离开木杆的顺序。 3. **输出结果** 输出每只蚂蚁离开木杆的时间及其编号。 --- #### Python 实现代码 以下是一个完整的 Python 实现: ```python t = int(input()) # 测试用例数量 for case in range(1, t + 1): n, l = map(int, input().split()) # 蚂蚁数量和木杆长度 ants = [] for _ in range(n): idx, pos, direction = input().split() idx = int(idx) pos = int(pos) if direction == 'L': time_to_fall = pos # 到达左边所需时间 else: time_to_fall = l - pos # 到达右边所需时间 ants.append((time_to_fall, idx)) # 按照掉落时间排序 sorted_ants_by_time = sorted(ants, key=lambda x: x[0]) # 提取原始索引以便后续匹配 original_indices = list(range(len(sorted_ants_by_time))) # 打印结果 print(f"Case #{case}:") for ant_index in original_indices: print(sorted_ants_by_time[ant_index][1], end=" ") print() ``` --- #### 关键点解释 1. **碰撞不影响总时间** 假设蚂蚁在碰撞时不改变方向,则整个过程中的大时间为任意一只蚂蚁到近端点的大距离。这使得我们可以跳过复杂的状态更新操作[^2]。 2. **效率优化** 使用内置函数 `sorted` 可以高效完成排序任务,算法整体复杂度为 \( O(N \log N) \)。 3. **边界条件** 特殊情况包括仅有一只蚂蚁的情况或者所有蚂蚁都朝同一方向移动的情形。程序应能正确处理此类场景。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值