代码思路:
本题如果直接用暴力求解的话只能得70分。
运用到了二维数组的前缀和,难点是如何求出二维数组的前缀和并计算出领域所有元素的和。
注意计算平均数的时候要保证精度相同,所有都要化为double型,否则会出错。
首先,我们需要读入输入数据,包括矩阵的大小 n,邻域的半径 r,阈值 t,以及给定的矩阵。为了方便后面的计算,我们可以将矩阵的外圈补零。
接下来,我们需要用前缀和求出每个位置的前缀和,即该位置左上角的所有元素之和。这样在计算某个位置的邻域和时可以通过前缀和算法在 O(1) 的时间复杂度内完成。
接下来,我们需要遍历整个矩阵,计算每个位置在给定半径和阈值下的邻域平均值是否小于等于给定阈值 t,如果是,则累加答案。
最后输出答案即可。
代码实现:
#include<bits/stdc++.h>
using namespace std;
int arr[700][700] = { 0 }; // 外圈补零
int main()
{
int n, L, r;
double t; // 注意修改阈值数据类型为 double
double ave = 0;
int Sum = 0;
cin >> n >> L >> r >> t;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cin >> arr[i][j];
}
}
for (int i = 1; i <= n; i++) // 求出前缀和
{
for (int j = 1; j <= n; j++)
{
arr[i][j] += arr[i - 1][j] + arr[i][j - 1] - arr[i - 1][j - 1];
//右下角+左下角+右上角-左上角,因为左上角的前缀和多加了一次
}
}
// 求出某个位置的邻域和
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
int up = (i - r) > 0 ? i - r : 1;
int down = (i + r) <= n ? i + r : n;
int right = (j + r) <= n ? j + r : n;
int left = (j - r) > 0 ? j - r : 1;
double num = (double)(right - left + 1) * (double)(down - up + 1);
//注意一定要化为double,否则结果会出错
ave = (arr[down][right] - arr[down][left - 1] - arr[up - 1][right] + arr[up - 1][left - 1]) / num;
if (ave <= t)
Sum++;
}
}
cout << Sum << endl; // 输出结果并换行
return 0;
}
总结:
- 掌握二维数组的前缀和求法。
- 可以采用外圈补零来统一求前缀和的过程
- 不用另设一个前缀和数组,直接在原数组上操作
- 除法时一定要统一精度