链接:P2706 巧克力 - 洛谷
问题描述:
我们需要从一个 n × m
的巧克力矩阵中找出一个不包含被老鼠洗劫过的格子(即值为0的格子)的最大矩形区域,使得该区域内的巧克力总数尽可能多。
解题思路:
由于数据规模为300,则我们必须在O(N^3)的时间进行求解。
显然,此问题就是求最大矩阵和,要求不能选择为0的点,所有我们只需要将值为0的点改写为 ( 负无穷),然后使用动态规划的思路,求—行列的最大子矩阵和,并且不断子矩阵和更新答案
代码实现:
#include <bits/stdc++.h>
using namespace std;
long long a[310][310]; // 存储巧克力数量
long long sum[310][310]; // 存储前缀和
const long long inf = -1e18; // 负无穷,表示被洗劫的格子
int main() {
int n, m;
cin >> n >> m;
long long ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
if (a[i][j] == 0) {
a[i][j] = inf; // 将被洗劫的格子设为负无穷
}
// 更新前缀和,计算当前行的前缀和
sum[i][j] = sum[i-1][j] + a[i][j];
}
}
// 遍历所有可能的行组合 i 到 j
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j++) {
long long ans1 = 0; // 当前矩形区域的巧克力数
// 遍历每一列
for (int k = 1; k <= m; k++) {
// 计算从行 i 到行 j 的当前列的巧克力数
ans1 += sum[j][k] - sum[i-1][k];
ans = max(ans, ans1); // 更新最大巧克力数
if (ans1 < 0) ans1 = 0; //重置为 0
}
}
}
cout << ans<<endl; // 输出最大巧克力数
return 0;
}