c++写7-51 子矩阵(NOIP-2014-普及组-4) 分数 100 作者 严华云 单位 湖州师范学院 题目.png 输入格式: 第一行包含用空格隔开的四个整数n,m,r,c,意义如问题描述中所述,每两个整数之间用一个空格隔开。 接下来的n行,每行包含m个用空格隔开的整数,用来表示问题描述中那个n行m列的矩阵。 输出格式: 输出共1行,包含1个整数,表示满足题目描述的子矩阵的最小分值。 输入样例: 5 5 2 3 9 3 3 3 9 9 4 8 7 4 1 7 4 6 6 6 8 5 6 9 7 4 5 6 1 输出样例: 6 【输入输出样例 1 说明】 该矩阵中分值最小的2行3列的子矩阵由原矩阵的第4行、第5行与第1列、第3列、第4列交叉位置的元素组成,为 21.png ,其分值为|6-5|+|5-6|+|7-5|+|5-6|+|6-7|+|5-5|+|6-6|=6。 【数据说明】 对于50%的数据,1≤n≤12,1≤m≤12, 矩阵中的每个元素1≤a[i][j]≤20; 对于100%的数据,1≤n≤16,1≤m≤16,矩阵中的每个元素1≤a[i][j]≤1000,1≤r≤n,1≤c≤m。
时间: 2024-03-23 17:37:00 浏览: 54
最大子矩阵-使用C++实现的最大子矩阵求和.zip
```c++
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20;
int n, m, r, c;
int a[N][N], row_median[N][N], col_median[N][N], abs_diff[N][N][N][N];
void init() // 预处理每个元素与其所在行和列的中位数之差的绝对值
{
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
{
int row_sum = 0, cnt = 0;
for (int k = j; k <= j + c - 1 && k <= m; k ++ ) // 求该元素所在行的和
{
row_sum += a[i][k];
cnt ++ ;
}
int row_avg = (row_sum + cnt - 1) / cnt; // 求该元素所在行的平均数
row_median[i][j] = row_avg; // 该元素所在行的中位数
}
for (int j = 1; j <= m; j ++ )
for (int i = 1; i <= n; i ++ )
{
int col_sum = 0, cnt = 0;
for (int k = i; k <= i + r - 1 && k <= n; k ++ ) // 求该元素所在列的和
{
col_sum += a[k][j];
cnt ++ ;
}
int col_avg = (col_sum + cnt - 1) / cnt; // 求该元素所在列的平均数
col_median[i][j] = col_avg; // 该元素所在列的中位数
}
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
for (int x = i; x <= i + r - 1 && x <= n; x ++ )
for (int y = j; y <= j + c - 1 && y <= m; y ++ )
abs_diff[i][j][x][y] = abs(a[x][y] - row_median[i][j]) + abs(a[x][y] - col_median[x][y]); // 该元素与其所在行和列的中位数之差的绝对值
}
int calc(int lx, int ly, int rx, int ry) // 计算子矩阵的分值
{
int res = 0;
for (int i = lx; i <= rx; i ++ ) // 计算每一行的和
res += col_median[i][ly] * (ry - ly + 1) - col_median[i][ly] * (ry - ly) / 2 + col_median[i][ry] * (ry - ly + 1) - col_median[i][ry] * (ry - ly) / 2;
for (int j = ly; j <= ry; j ++ ) // 计算每一列的和
res += row_median[lx][j] * (rx - lx + 1) - row_median[lx][j] * (rx - lx) / 2 + row_median[rx][j] * (rx - lx + 1) - row_median[rx][j] * (rx - lx) / 2;
for (int i = lx; i <= rx; i ++ )
for (int j = ly; j <= ry; j ++ )
res += abs_diff[lx][ly][i][j]; // 计算该子矩阵内每个元素与其所在行和列的中位数之差的绝对值之和
return res;
}
int main()
{
cin >> n >> m >> r >> c;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
cin >> a[i][j];
init(); // 预处理每个元素与其所在行和列的中位数之差的绝对值
int res = 0x3f3f3f3f;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
for (int x = i; x <= n; x ++ )
for (int y = j; y <= m; y ++ )
if (x - i + 1 >= r && y - j + 1 >= c) // 子矩阵大小满足要求
res = min(res, calc(i, j, x, y)); // 更新答案
cout << res << endl;
return 0;
}
```
阅读全文