UVA114 Simulation Wizardry

发布时间 2023-08-05 08:34:40作者: JRcxy

UVA114 Simulation Wizardry

题目传送门

此题为模拟类型,必须认真读题,绝不能漏掉任何一个细节。

分析

解释代码中的主要部分:

  1. 结构体定义:struct POINT 用于表示二维坐标,struct BUMPER 用于表示弹板的信息,包括分值和消耗。

  2. pTable 数组:用于记录所有弹板的信息。数组的索引对应表面上的网格点,每个网格点上可能有一个弹板,通过指针 BUMPER* 存储弹板的信息。

  3. aDir 数组:表示四个方向,即向上、向右、向下、向左。

  4. 输入部分:程序首先从标准输入读取表面的尺寸、墙的消耗、弹板数量,然后循环读入每个弹板的坐标、分值和消耗,并将弹板信息存储到 pTable 数组中。

  5. 循环模拟每个球的移动:程序继续从标准输入读入每个球的起始坐标、起始方向和生命值。然后,通过一个嵌套循环来模拟每个球的移动过程。在每个时间步中,程序计算球在新位置的坐标,检查是否撞墙或撞击保险杠,根据撞击的情况更新球的分值和生命值,以及改变球的方向。循环终止条件是球的生命值小于等于 \(0\),表示球消失从表面。

  6. 输出:对于每个球,程序会输出球在每次撞击保险杠时得到的分值,然后将这一次撞击得到的分值累加到总分中。最后,程序输出所有球撞击保险杠得到的总分。需要注意的一些问题:

    • 表面网格的坐标从左下角开始,而数组索引是从 \(0\) 开始的,因此在读入弹板和球的坐标时需要适配数组索引。
    • 碰撞墙壁或保险杠时,球的方向会改变。具体地,撞墙时顺时针旋转 \(90\) 度,撞保险杠时逆时针旋转 \(90\) 度。
    • 每个球在撞击保险杠或墙壁时都会消耗生命值,生命值小于等于 \(0\) 时球消失。

下面奉上代码……

AC Code

#include <iostream>
using namespace std;
struct POINT { int x; int y; };
//记录弹板信息的结构体
struct BUMPER { int nValue; int nCost; };
int main(void) {
    //用二维数组记录所有弹板的信息,不存在弹板的位置为空指针
    BUMPER *pTable[52][52] = {0}, *pBumper;
    //按照题目指定的方向编号,设定移动偏移量
    POINT ptSize, ptPos, aDir[4] = { {1, 0}, {0, 1}, {-1, 0}, {0, -1} };
    int nWCost, nTotal = 0, nValue, nLife, nDir;
    //输入桌面尺寸、墙的消耗、弹板数量
    for (cin >> ptSize.x >> ptSize.y >> nWCost >> nTotal; nTotal-- > 0; ) {
        //循环读入每个弹板的坐标、分值以及消耗,并存入数组
        cin >> ptPos.x >> ptPos.y;
        pBumper = new BUMPER;
        cin >> pBumper->nValue >> pBumper->nCost;
        //弹板的坐标是以1起始的,需适配以0起始的数组地址
        pTable[ptPos.x - 1][ptPos.y - 1] = pBumper;
    }
    //桌面尺寸也需适配以0起始的数组地址
    ptSize.x -= 1, ptSize.y -= 1;
    //循环读入每个球的起始坐标,起始方向和生命值
    for (nTotal = 0; cin >> ptPos.x >> ptPos.y >> nDir >> nLife;) {
        //使坐标适配数组地址
        --ptPos.x, --ptPos.y;
        //循环移动小球,直到生命结束
        for (nValue = 0; --nLife > 0; ) {
            //建立新坐标变量存储移动后的值,以便移动失败时回退
            POINT ptNew = {ptPos.x + aDir[nDir].x, ptPos.y + aDir[nDir].y};
            //撞墙
            if (ptNew.x == ptSize.x || ptNew.y == ptSize.y ||
                ptNew.x < 1 || ptNew.y < 1) {
                //生命值减去墙的消耗并转向
                nLife -= nWCost;
                nDir = (nDir + 3) % 4;
                continue;
            }
            //碰到弹板
            if ((pBumper = pTable[ptNew.x][ptNew.y]) != 0) {
                //分值加上弹板的分值,生命值减去消耗并转向
                nValue += pBumper->nValue;
                nLife -= pBumper->nCost;
                nDir = (nDir + 3) % 4;
                continue;
            }
            //移动到空白格子
            ptPos = ptNew;
        }
        //总分累加这一次的分值并输出当前分值
        nTotal += nValue;
        cout << nValue << endl;
    }
    //输出总分,程序结束
    cout << nTotal << endl;
    return 0;
}