1.题目描述
小蓝负责花园的灌溉工作。
花园可以看成一个 n 行 m 列的方格图形。中间有一部分位置上安装有出水管。
小蓝可以控制一个按钮同时打开所有的出水管,打开时,有出水管的位置可以被认为已经灌溉好。
每经过一分钟,水就会向四面扩展一个方格,被扩展到的方格可以被认为已经灌溉好。即如果前一分钟某一个方格被灌溉好,则下一分钟它上下左右的四个方格也被灌溉好。
给定花园水管的位置,请问 𝑘k 分钟后,有多少个方格被灌溉好?
输入描述
输入的第一行包含两个整数 n,m。
第二行包含一个整数 t,表示出水管的数量。
接下来 t 行描述出水管的位置,其中第 𝑖i 行包含两个数 r,c 表示第 r 行第 c 列有一个排水管。
接下来一行包含一个整数 k。
其中,1≤n,m≤100,1≤t≤10,1≤k≤100。
输出描述
输出一个整数,表示答案。
输入输出样例
示例 1
输入
3 6
2
2 2
3 4
1
输出
9
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
2.代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m,t,r,c,k;
cin>>n>>m;
cin>>t;
int cc[n+2][m+2]={0};
int nextcc[n+2][m+2]={0};//开两个二维数组,初始化为0
while(t--)
{
cin>>r>>c;
cc[r][c]=1;//被灌溉过的格子标记为1
}
cin>>k;
int dx[]={-1,0,0,1};//定义两个数组,来模拟坐标的移动(是个很实用的小技巧)
int dy[]={0,1,-1,0};
while(k--)
{
memcpy(nextcc,cc,sizeof cc);//将cc所指向的内存区域的内容复制到nextcc所指向的内存区域,复制的字节数为sizeof cc
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(nextcc[i][j]==1)//当前遍历到的方格是否在上一秒已经被灌溉过
{
for(int p=0;p<4;p++)
{
int x1=i+dx[p],y1=j+dy[p];
if(x1>=1&&x1<=n&&y1>=1&&y1<=m)
{
cc[x1][y1]=1;
}
}
}
}
}
}
int cnt=0;//计数
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(cc[i][j]==1) cnt++;
}
}
cout<<cnt<<endl;
}
3.题目难点
1.难点这个题目的难点在哪里:
主要难点在于如何正确地模拟水的扩散过程,并且保证每一秒的扩散都是基于上一秒已经扩散好的状态进行的。如果不使用备份数组,直接在原数组上更新,会导致在遍历过程中使用了本秒更新的状态,从而产生错误的结果。
简单来说,在扩散过程中,如果不使用备份数组,当遍历到一个方格并更新其周围方格后,后续遍历可能会再次遇到刚刚更新的方格,这样就会错误地认为这些方格在本秒也被扩散了,而实际上它们是在本秒被更新的状态下被遍历到的。为了避免这种情况,需要一个备份数组`nestcc`来记录上一秒的状态,确保每一秒的扩散都是基于上一秒已经扩散好的状态进行的。这样,`cc`用于判断是否需要扩散,而`cc`用于记录当前秒数的扩散结果。
2. nextcc和cc的作用:
`cc`数组用于记录当前秒数下每个方格是否已经被灌溉。
`nextcc`数组是`cc`数组的备份,用于记录上一秒每个方格是否已经被灌溉。这样在每一秒的扩散过程中,可以确保只基于上一秒的状态进行扩散,避免使用本秒更新的状态。