1 条题解

  • 0
    @ 2025-5-6 17:55:45

    题意分析

    120×120120\times120 像素的网格路径上,若干辆坦克可沿每隔 10 像素的水平或垂直路径移动、转向或开火。给定每辆坦克的初始位置、朝向,以及按时间顺序到达的控制命令序列,模拟坦克和子弹的行为,直到所有命令执行完毕且战场上无子弹为止,输出最后存活的一辆坦克名称,否则则输出NO WINNER!。


    解题思路

    • 离散化路径:将坐标 0,10,,1200,10,\dots,120 对应为离散格点 0,1,,120,1,\dots,12,移动速度 10,10,像素/秒 即每秒走 1 格;子弹速度 20 像素/秒 即每秒走 2 格。

    • 时间效果实现:以最小时间单位 0.1,0.1,秒或直接按整数秒再细分命令与运动可混合处理,但推荐将时间戳和格数都离散化为一份进行,需要循环从 t=0t=0 开始,进行以下步骤:

      1. 子弹更新:先移动所有存活子弹,并检测是否击中坦克或出界;
      2. 坦克命令:执行所有在当前时刻到达的命令(MOVE/STOP/TURN/SHOOT);
      3. 坦克移动:移动所有标记为存活的坦克;
      4. 终止检测:当所有命令已处理且无子弹存活时结束。
    • 存活状态判定:坦克和子弹都进行标记;坦克被击中瞬间置为死并移出映射,同时子弹击中或出界后置为死。结束后统计存活坦克数,若恰为 1 则输出其名字,反之则输出 NO WINNER!。


    本题代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    using namespace std;
    
    const int MAXN = 10;
    const int MAXM = 1000;
    const int GRID = 13;     // 0..12 共 13 格
    const int MAXB = 1005;   // 最多子弹数
    
    struct Tank {
        string name;
        int x, y;      // 0..12 格
        int dir;       // 0=右,90=上,180=左,270=下
        bool moving;
        bool alive;
    } tanks[MAXN];
    
    struct Bullet {
        int x, y;
        int dir;
        bool alive;
    } bullets[MAXB];
    
    struct Cmd {
        int time;       // 离散时间,单位:格/秒
        string name;
        string type;
        int angle;      // TURN 时的角度,否则忽略
    } cmds[MAXM];
    
    int tankMap[GRID][GRID];
    int bulletMap[GRID][GRID];
    
    int dx[4] = {1, 0, -1, 0};   // dir=0,90,180,270 对应索引 0,1,2,3
    int dy[4] = {0, 1, 0, -1};
    
    int dirIndex(int d) {
        if (d == 0)   return 0;
        if (d == 90)  return 1;
        if (d == 180) return 2;
        return 3;
    }
    
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
    
        int N, M;
        while (cin >> N >> M) {
            if (N==0 && M==0) break;
            // 初始化
            memset(tankMap, -1, sizeof(tankMap));
            for (int i = 0; i < N; i++) {
                tanks[i].alive = true;
                tanks[i].moving = false;
                cin >> tanks[i].name;
                int px, py;
                cin >> px >> py >> tanks[i].dir;
                tanks[i].x = px / 10;
                tanks[i].y = py / 10;
                tankMap[tanks[i].x][tanks[i].y] = i;
            }
            // 读命令,时间离散化:每秒6格 -> *6
            for (int i = 0; i < M; i++) {
                cin >> cmds[i].time >> cmds[i].name >> cmds[i].type;
                if (cmds[i].type == "TURN")
                    cin >> cmds[i].angle;
                cmds[i].time *= 6;
            }
            // 模拟
            memset(bulletMap, -1, sizeof(bulletMap));
            for (int i = 0; i < MAXB; i++) bullets[i].alive = false;
            int bulletCnt = 0, cmdPtr = 0;
            // 时间上限:命令最后时刻 + 额外子弹飞行时间
            int t = 0;
            while (true) {
                // 清空子弹映射,重建
                memset(bulletMap, -1, sizeof(bulletMap));
                for (int i = 0; i < bulletCnt; i++)
                    if (bullets[i].alive)
                        bulletMap[bullets[i].x][bullets[i].y] = i;
    
                // 子弹击中检测
                for (int i = 0; i < bulletCnt; i++) {
                    if (!bullets[i].alive) continue;
                    int bx = bullets[i].x, by = bullets[i].y;
                    if (tankMap[bx][by] != -1) {
                        int ti = tankMap[bx][by];
                        tanks[ti].alive = false;
                        tankMap[bx][by] = -1;
                        bullets[i].alive = false;
                    }
                }
    
                // 执行当前时刻命令
                while (cmdPtr < M && cmds[cmdPtr].time == t) {
                    for (int i = 0; i < N; i++) if (tanks[i].alive && tanks[i].name == cmds[cmdPtr].name) {
                        auto &tk = tanks[i];
                        if (cmds[cmdPtr].type == "MOVE")      tk.moving = true;
                        else if (cmds[cmdPtr].type == "STOP")  tk.moving = false;
                        else if (cmds[cmdPtr].type == "TURN")  tk.dir = (tk.dir + cmds[cmdPtr].angle + 360) % 360;
                        else if (cmds[cmdPtr].type == "SHOOT") {
                            bullets[bulletCnt] = {tk.x, tk.y, tk.dir, true};
                            bulletCnt++;
                        }
                        break;
                    }
                    cmdPtr++;
                }
    
                // 子弹移动
                for (int i = 0; i < bulletCnt; i++) {
                    if (!bullets[i].alive) continue;
                    int idx = dirIndex(bullets[i].dir);
                    int nx = bullets[i].x + 2*dx[idx];
                    int ny = bullets[i].y + 2*dy[idx];
                    if (nx<0 || nx>=GRID || ny<0 || ny>=GRID) {
                        bullets[i].alive = false;
                    } else {
                        bullets[i].x = nx;
                        bullets[i].y = ny;
                    }
                }
    
                // 坦克移动
                for (int i = 0; i < N; i++) {
                    if (!tanks[i].alive || !tanks[i].moving) continue;
                    auto &tk = tanks[i];
                    tankMap[tk.x][tk.y] = -1;
                    int idx = dirIndex(tk.dir);
                    int nx = tk.x + dx[idx];
                    int ny = tk.y + dy[idx];
                    if (nx<0||nx>=GRID||ny<0||ny>=GRID) {
                        tk.moving = false;
                    } else {
                        tk.x = nx; tk.y = ny;
                    }
                    tankMap[tk.x][tk.y] = i;
                }
    
                // 终止条件:命令已执行完且无子弹存活
                bool bulletsAlive = false;
                for (int i = 0; i < bulletCnt; i++)
                    if (bullets[i].alive) { bulletsAlive = true; break; }
                if (cmdPtr==M && !bulletsAlive) break;
    
                t++;
            }
    
            // 输出结果
            int aliveCnt = 0; string winner;
            for (int i = 0; i < N; i++) {
                if (tanks[i].alive) {
                    aliveCnt++; winner = tanks[i].name;
                }
            }
            if (aliveCnt == 1) cout << winner << "\n";
            else cout << "NO WINNER!\n";
        }
        return 0;
    }
    
    
    
    • 1

    信息

    ID
    1729
    时间
    2000ms
    内存
    64MiB
    难度
    10
    标签
    递交数
    15
    已通过
    1
    上传者