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)游戏的布局,当然也许不是,毕竟我也没接触过……

浙公网安备 33010602011771号