P1789 【MC生存】插火把

题目描述

话说有一天 linyorson 在“我的世界”开了一个 \(n \times n\) 的方阵,现在他有 \(m\) 个火把和 \(k\) 个萤石,分别放在 \((x_1, y_1) \sim (x_m, y_m)\)\((o_1, p_1) \sim (o_k, p_k)\) 的位置,没有光并且没放东西的地方会生成怪物。请问在这个方阵中有几个点会生成怪物?

注意,在本题中火把与萤石的照明范围与原版 Minecraft(我的世界)不尽相同,请以本题中的描述为准。

P.S. 火把的照亮范围是:

火把

萤石:

萤石

输入格式

输入共 \(m + k + 1\) 行。
第一行为 \(n, m, k\)
\(2\) 到第 \(m + 1\) 行分别是火把的位置 \(x_i, y_i\)
\(m + 2\) 到第 \(m + k + 1\) 行分别是萤石的位置 \(o_i, p_i\)

注:可能没有萤石,但一定有火把。

输出格式

有几个点会生出怪物。


问题分析

这题很明显可以用数组的知识解决。将发光的坐标和不发光的坐标分别用0和1表示,两种情况相叠时不难发现——发光与发光相叠为发光,不发光与不发光相叠为不发光,发光与不发光相叠时为发光,因此运算符选用

很明显我们要选用二维数组。既然用到数组,而且给出的也是放置火把和萤石的坐标,那么就要牵涉到一个坐标偏移的问题了。给出的坐标位置对应的是火把或萤石数组位于\((2,2)\)处,因此在进行\(for\)循环时,需要把初始横纵坐标调整为:

\(i_{min}=x_0-2-1\)

\(j_{min}=y_0-2-1\)

有人可能要问了,为什么要多减一个1?因为题目给定的是坐标,我们这里的得出的是数组索引。末尾坐标倒不需要,毕竟最大值也是到\(n-1\).

\(i_{max}=x_0+2\)

\(j_{max}=y_0+2\)

还有一个问题,万一有一排或者有一列处于边界外该怎么处理?这就是循环中需要讨论的边界情况了。这里由于索引被限制在\([0,n-1]\)这个区间里,我们很自然想到用求得的初始坐标和末尾坐标分别与边界值\(0\)\(n-1\)比较,超出边界就取边界值。这里为了方便建议使用std::max()std::min()函数取值。

整个运算的流程按照上面的说法是这样的:

Area[i][j]=Area[i][j]|torch[i-y+3][j-x+3];
//元素之间的运算以及坐标的变换
for(int i=std::max(0,y-3); i<std::min(n,y+2); ++i)
//以行为例,边界判断

剩下的就简单了,构造一个初始值为全0的二维数组作为最初不发光的区块,每放置一个发光物件就进行一次运算,最后统计发光坐标,也就是二维数组中1的个数


变量初始化

我们再讨论一下里面牵涉到的三个需要初始化的变量。区块数组、火把数组、萤石数组

区块数组初始化默认为全0,因为初始状态下全为不发光。

火把数组根据题意,应该是长这样的:

bool torch[5][5]=
{
    {0,0,1,0,0},
    {0,1,1,1,0},
    {1,1,1,1,1},
    {0,1,1,1,0},
    {0,0,1,0,0}
};//火把

同理,萤石数组根据题意,应该长这样:

bool glowstone[5][5]
{
    {1,1,1,1,1},
    {1,1,1,1,1},
    {1,1,1,1,1},
    {1,1,1,1,1},
    {1,1,1,1,1}
};

代码

#include<iostream>

//P1789 【Mc生存】插火把
bool torch[5][5]=
{
    {0,0,1,0,0},
    {0,1,1,1,0},
    {1,1,1,1,1},
    {0,1,1,1,0},
    {0,0,1,0,0}
};

bool glowstone[5][5]
{
    {1,1,1,1,1},
    {1,1,1,1,1},
    {1,1,1,1,1},
    {1,1,1,1,1},
    {1,1,1,1,1}
};

int main(){
    int n,m,k; std::cin>>n>>m>>k;
    int flag=0;

    bool Area[114][114]={0};

    for(int i=0; i<m; ++i)
    {
        int x,y; std::cin>>x>>y;

        for(int i=std::max(0,y-3); i<std::min(n,y+2); ++i)
        {
            for(int j=std::max(0,x-3); j<std::min(n,x+2); ++j)
            {
                Area[i][j]=Area[i][j]|torch[i-y+3][j-x+3];
            }
        }
    }

    for(int i=0; i<k; ++i)
    {
        int x,y; std::cin>>x>>y;

        for(int i=std::max(0,y-3); i<std::min(n,y+2); ++i)
        {
            for(int j=std::max(0,x-3); j<std::min(n,x+2); ++j)
            {
                Area[i][j]=Area[i][j]|glowstone[i-y+3][j-x+3];
            }
        }
    }

    for(int i=0; i<n; ++i)
    {
        for(int j=0; j<n; ++j)
        {
            if(Area[i][j]==0) flag++;
        }
    }

    std::cout<<flag<<std::endl;
}

其实我感觉这个解题思路很像一些(2D)游戏的布局,当然也许不是,毕竟我也没接触过……

posted @ 2025-07-12 14:28  一说米  阅读(80)  评论(2)    收藏  举报
© 2026 ESL One 一说米|Powered by 博客园