时间限制:C/C++语言 1000MS;其他语言 3000MS
内存限制:C/C++语言 65536KB;其他语言 589824KB
题目描述:
若[i,j]和[i’,j’]是矩阵的两个位置, 他们的距离定义为max(|i-i’|, |j-j’|)。已知:
1. 整数 n > r >= 0;
2. F为 n * n 的矩阵, 矩阵内元素属于集合{0, 1};
3. 矩阵第i列第j行的元素用F[i,j]表示.
请编写程序,输出一个 n * n 的W矩阵。要求W[i,j] (矩阵W第i列第j行的元素)等于所有可能的F[x,y]的和, 其中[x,y]取和[i,j]的距离不大于r的所有位置。
输入
输入的第一行包含两个正整数n和r, 用一个空格隔开: 0 <= r < n <= 250。接下来会有n行表示矩阵F的元素, 每一行包含n个整数∈{0,1},用一个空格隔开。
输出
将来结果打印到标准输入输出。输出为n行,在第j行, 应该输出W[1,j]~W[n,j];每个元素中间用一个空格隔开。
样例输入
5 1
1 0 0 0 1
1 1 1 0 0
1 0 0 0 0
0 0 0 1 1
0 1 0 0 0
样例输出
3 4 2 2 1
4 5 2 2 1
3 4 3 3 2
2 2 2 2 2
1 1 2 2 2
暴力求解
#include <iostream>
#include <vector>
using namespace std;
int test(){
int n, r;
cin >> n >> r;
vector<vector<int>> F(n, vector<int>(n, 0));
vector<vector<int>> W(n, vector<int>(n, 0));
int temp;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> F[i][j];
// 对于每个W[i,j]
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
{
int startX = i - r >= 0 ? i - r : 0;
int startY = j - r >= 0 ? j - r : 0;
int endX = i + r < n ? i + r : n - 1;
int endY = j + r < n ? j + r : n - 1;
for (int m = startX; m <= endX; m++)
for (int n = startY; n <= endY; n++)
W[i][j] += F[m][n];
}
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cout << W[i][j] << (j == n - 1 ? "\n" : " ");
return 0;
}
上述方法因为在内层求和数涉及重复计算,所以时间复杂度略高(其复杂度为 O(n2×r2) ),可以参考其他思路(积分图)进行实现,如何减少重复计算呢?
积分矩阵可以事先求出(画一下图就知道很容易求得),其复杂度为 O(n2) ,然后利用S矩阵就可以快速求出要求的区域的和,这一步复杂度仍为 O(n2) ,最终整体复杂度为 O(n2) 。
源码
#include <iostream>
#include <vector>
using namespace std;
int test(){
int n, r;
cin >> n >> r;
vector<vector<int>> F(n, vector<int>(n, 0));
vector<vector<int>> S(n, vector<int>(n, 0));
vector<vector<int>> W(n, vector<int>(n, 0));
int temp;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> F[i][j];
// 求S矩阵
// i=0时
S[0][0] = F[0][0];
for (int i = 1; i < n; i++){
S[i][0] = S[i - 1][0] + F[i][0];
}
// i=0时
for (int j = 1; j < n; j++){
S[0][j] = S[0][j - 1] + F[0][j];
}
// i,j>0时
for (int i = 1; i < n; i++)
for (int j = 1; j < n; j++)
S[i][j] = S[i][j - 1] + S[i - 1][j] - S[i - 1][j - 1] + F[i][j];
// 对于每个W[i,j]
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
{
// 注意越界,边界条件
int startX = i - r >= 0 ? i - r : 0;
int startY = j - r >= 0 ? j - r : 0;
int endX = i + r < n ? i + r : n - 1;
int endY = j + r < n ? j + r : n - 1;
W[i][j] = S[endX][endY]
- (startY - 1 < 0 ? 0 : S[endX][startY - 1])
- (startX - 1 < 0 ? 0 : S[startX - 1][endY])
+ (startX - 1 < 0 || startY - 1 < 0 ? 0 : S[startX - 1][startY - 1]);
}
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cout << W[i][j] << (j == n - 1 ? "\n" : " ");
return 0;
}