这是一道用二维前缀和算法解决的题目,题目的要求是求出最大的平衡子矩形包含了多少个格子。所谓平衡子矩形就是黑格子数和白格子数相等。先看输入,输入是一个01串,所以我们不能简单的用整型的二维数组进行保存,这里我们可以使用字符串数组。其次,对于黑格子数和白格子数相等,我们可以分别统计黑格子和白格子的数量。不过,这里我们有一个更好的方法就是,将白格子(0)变成-1,这样我们只需要看这个区域内的所有格子相加是否为0即可。省去了统计格子0和1这一步。既然是区域,我们就需要用到二维前缀和。用二维前缀和求出以(i,j)为右下角(0,0)为左上角的0和1相加的情况,对于二维前缀和的求法,见下图
我们看这个图,假如我们想对黄色区域进行求前缀和
就需要将蓝色区域和绿色区域的和进行相加,并减去公共区域(打X的区域)。
求出二维前缀和之后,我们枚举每一个区域,在枚举的过程中,同时计算该区域内黑白格子数目是否相等(-1和1相加是否等于0),在满足条件的区域内,寻找格子数最多的进行输出即可。
#include <iostream>
#include <string>
using namespace std;
string str[15];
int s[15][15];
int a[15][15];
int main() {
int n, m; cin >> n >> m;
int _max = 0;
for (int i = 1; i <= n;i++) {
cin >> str[i];
}
for (int i = 1; i <=n;i++) {
for (int j = 1; j <=m;j++) {
if (str[i][j-1] == '1') {
s[i][j] = 1;
}
else s[i][j] = -1;
a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + s[i][j];
}
}
for (int si = 1; si <= n;si++) {
for (int sj = 1; sj <= m;sj++) {
for (int ei = si; ei <= n;ei++) {
for (int ej = sj; ej <= m;ej++) {
int sum = a[ei][ej] - a[si - 1][ej] - a[ei][sj - 1]+a[si-1][sj-1];
if (sum == 0 && _max < (ei - si + 1) * (ej - sj + 1))_max = (ei - si + 1) * (ej - sj + 1);
}
}
}
}
cout << _max;
return 0;
}
在遍历字符串数组的同时,将其转换成整型数据,方便二维前缀和的求解;
其中sum = a[ei][ej] - a[si - 1][ej] - a[ei][sj - 1]+a[si-1][sj-1]中+a[si-1][sj-1]是因为多减了一次