UVa 10156 Sala-ma-Sond A Nice Little Pond

题目描述

本题要求模拟一个矩形池塘中多只乌龟的移动行为。池塘被建模为一个 N×MN \times MN×M 的网格,乌龟位于网格的整数坐标位置上。每只乌龟可以接受八个方向的移动指令:NSEWNENWSESW。移动规则如下:

  • 如果目标位置超出网格边界,移动被忽略;
  • 如果目标位置已被其他乌龟占据,移动被忽略;
  • 否则,乌龟移动到目标位置。

输入包含多个数据集,每个数据集给出池塘尺寸、乌龟初始位置和一系列移动指令。要求输出所有指令执行后的池塘状态图。

输入格式

  • 第一行四个整数:NNN MMM TTT KKK
    • NNN:南北方向网格数
    • MMM:东西方向网格数
    • TTT:乌龟数量
    • KKK:移动指令数
  • 接下来 TTT 行,每行三个整数:乌龟 ID\texttt{ID}ID 初始行坐标 初始列坐标
  • 接下来 KKK 行,每行一个乌龟 ID\texttt{ID}ID 和一个方向字符串

输出格式

  • 用 ASCII 字符绘制 NNN 行网格图
  • 有乌龟的位置输出 *,空位置输出空格
  • 每行末尾不能有空格
  • 每个数据集后输出一个空行

解题思路

问题分析

本题属于网格模拟类问题,需要处理多个对象在有限空间中的移动,并检测位置冲突。关键在于高效地跟踪每个乌龟的位置,并在移动时快速判断目标位置的合法性。

数据结构设计

  1. 乌龟位置存储:使用 std::map<int, std::pair<int, int>> 将乌龟 ID\text{ID}ID 映射到坐标位置,便于通过 ID\texttt{ID}ID 快速查找。

  2. 位置占用标记:使用二维数组 vector<vector<bool>> occupied 记录每个网格位置是否被占用,实现 O(1)O(1)O(1) 时间的冲突检测。

  3. 方向映射:使用 std::map<std::string, std::pair<int, int>> 将方向字符串映射为坐标偏移量。

算法流程

  1. 初始化阶段

    • 读取池塘尺寸和乌龟数量
    • 记录每只乌龟的初始位置
    • 初始化位置占用标记数组
  2. 指令处理阶段

    • 对于每个移动指令:
      • 检查乌龟 ID\texttt{ID}ID 是否存在
      • 计算目标坐标
      • 检查边界和位置冲突
      • 如果移动合法,更新乌龟位置和占用标记
  3. 输出阶段

    • 根据最终位置填充字符网格
    • 逐行输出,去除行尾空格
    • 输出数据集间的空行

复杂度分析

  • 时间复杂度:O(K+N×M)O(K + N \times M)O(K+N×M),其中 KKK 是指令数,N×MN \times MN×M 是输出网格大小
  • 空间复杂度:O(N×M+T)O(N \times M + T)O(N×M+T),用于存储网格和乌龟位置

代码实现

// Sala-ma-Sond A Nice Little Pond
// UVa ID: 10156
// Verdict: Accepted
// Submission Date: 2025-11-23
// UVa Run Time: 0.110s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, m, t, k;
    // 处理多个数据集
    while (cin >> n >> m >> t >> k) {
        // 存储乌龟ID到坐标的映射
        map<int, pair<int, int>> turtles;
        // 标记网格位置是否被占用
        vector<vector<bool>> occupied(n, vector<bool>(m, false));
        
        // 读取乌龟初始位置
        for (int i = 0; i < t; i++) {
            int id, x, y;
            cin >> id >> x >> y;
            turtles[id] = {x, y};
            occupied[x][y] = true;
        }

        // 定义八个方向的坐标偏移量
        map<string, pair<int, int>> dirs = {
            {"N", {-1, 0}}, {"S", {1, 0}}, {"E", {0, 1}}, {"W", {0, -1}},
            {"NE", {-1, 1}}, {"NW", {-1, -1}}, {"SE", {1, 1}}, {"SW", {1, -1}}
        };

        // 处理移动指令
        for (int i = 0; i < k; i++) {
            int id;
            string dir;
            cin >> id >> dir;
            // 检查乌龟ID是否存在
            if (turtles.find(id) == turtles.end()) continue;
            
            // 获取当前位置
            int x = turtles[id].first, y = turtles[id].second;
            // 计算目标位置
            int dx = dirs[dir].first, dy = dirs[dir].second;
            int nx = x + dx, ny = y + dy;
            
            // 检查边界
            if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
            // 检查位置冲突
            if (occupied[nx][ny]) continue;
            
            // 更新位置:先释放原位置,再占用新位置
            occupied[x][y] = false;
            occupied[nx][ny] = true;
            turtles[id] = {nx, ny};
        }

        // 输出最终状态
        for (int i = 0; i < n; i++) {
            string line = "";
            for (int j = 0; j < m; j++) {
                if (occupied[i][j]) line += '*';
                else line += ' ';
            }
            // 去除行尾空格
            while (!line.empty() && line.back() == ' ') line.pop_back();
            cout << line << endl;
        }
        cout << endl;
    }
    return 0;
}

关键要点

  1. 高效冲突检测:使用二维数组记录位置占用状态,避免每次遍历所有乌龟
  2. 原子性更新:移动时同时更新原位置和新位置的占用状态,保持数据一致性
  3. 输出格式控制:严格按要求去除行尾空格,确保格式正确
  4. 边界处理:仔细检查网格边界和乌龟 ID\texttt{ID}ID 的有效性

该解法通过合理的数据结构设计和细致的边界处理,能够高效正确地模拟乌龟在池塘中的移动行为。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值