题意
给出n*m的矩阵,可以横着切一刀或是竖着切一刀,问切完后两块和的差值的最小值
思路1:暴力枚举
首先能想到的是O(n^3)的暴力,以横着切一刀为例,枚举切的位置是i,那么1~i 行的元素之和就是第一块的值s1,i+1~n行的元素之和就是第二块的值s2,大概的代码如下
for i := 1; i <= n; i++ {
//切的位置
var s1,s2 int64 = 0,0
for k := 1; k <= i; k ++ {
for j := 1; j <= m; j ++ {
s1 += int64(a[k][j])
}
}
for k := i+1; k <= n; k ++ {
for j := 1; j <= m; j ++ {
s2 += int64(a[k][j])
}
}
ans = min(ans,abs(s1-s2))
}
思路2:一维前缀和
思路1会有很多重复计算的地方,而且数组a是不变的数组,所以可以预处理下需要计算的信息,以减少时间复杂度。
还是以横着切为例,枚举当前切的位置为i,那么对于每个位置i来说,第一块的面积是前i行矩阵元素的和,第二块的面积是i+1行到n行矩阵元素的和,那么我们只需要用前缀和数组sum1[x]表示前x行矩阵元素的和就可以了。
竖着切也同理。
golang代码一直超时只能用cpp写了,要注意开long long
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> a(n + 1, vector<int>(m + 1));
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
cin >> a[i][j];
}
}
vector<long long> sum1(n + 1, 0), sum2(m + 1, 0);
for (int i = 1; i <= n; ++i) {
int tmp = 0;
for (int j = 1; j <= m; ++j) {
tmp += a[i][j];
}
sum1[i] = sum1[i - 1] + tmp;
}
for (int j = 1; j <= m; ++j) {
int tmp = 0;
for (int i = 1; i <= n; ++i) {
tmp += a[i][j];
}
sum2[j] = sum2[j - 1] + tmp;
}
long long ans = 1e9;
for (int i = 1; i <= n; ++i) {
long long s1 = sum1[i] - sum1[0];
long long s2 = sum1[n] - sum1[i];
ans = min(ans, abs(s1 - s2));
}
for (int j = 1; j <= m; ++j) {
long long s1 = sum2[j] - sum2[0];
long long s2 = sum2[m] - sum2[j];
ans = min(ans, abs(s1 - s2));
}
cout << ans << endl;
return 0;
}
思路3:二维前缀和
核心点和思路2一样,不过换了种实现方法。
还是以横着切为例,如果当前切的位置是i的话,那么第一块的大小是sum[i][m] ,第二块的大小是sum[n][m]-sum[i][m],这样的话就是默认把左上角的节点看成矩形的左上角。
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> a(n + 1, vector<int>(m + 1));
vector<vector<long long>> sum(n + 1, vector<long long>(m + 1, 0));
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
cin >> a[i][j];
sum[i][j] = sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1] + a[i][j];
}
}
long long ans = 1e9;
// 枚举横着切还是竖着切
for (int i = 1; i <= n; ++i) {
ans = min(ans, abs(sum[n][m] - sum[i][m] * 2));
}
for (int j = 1; j <= m; ++j) {
ans = min(ans, abs(sum[n][m] - sum[n][j] * 2));
}
cout << ans << endl;
return 0;
}

京公网安备 11010502036488号