题目地址:
https://leetcode.com/problems/maximum-score-from-grid-operations/description/
给定一个 n × n n\times n n×n的非负整数矩阵 a a a,允许在任意多列从上到下连续的格子涂黑色,涂完颜色之后,如果一个白色格子(即未涂色的格子)在横的方向与黑格子相邻,则该白色格子可以计入得分。对于所有的涂色方案,问最大总分是多少。
设 f [ i ] [ j ] f[i][j] f[i][j]表示只考虑 a a a的前 i i i列,且第 i − 1 i-1 i−1列(从 0 0 0计数)涂 j j j个格子的情况下,能得到的最大得分。我们枚举第 i − 2 i-2 i−2列涂了多少个格子,假设涂 k k k个。如果 k > j k>j k>j,那么我们只需要在 f [ i − 1 ] [ k ] f[i-1][k] f[i−1][k]基础上加上第 i i i列从 j j j到 k k k之间的白色格子的分数就行了;但是如果 k < j k<j k<j的话,我们无法判断 i − 1 i-1 i−1列从 k k k到 j j j的格子是否要计入答案,因为这一段格子可能是由其左边的那一列贡献,也可能由右边的那一列贡献。
我们再增加一维,设 f [ i ] [ j ] [ 0 ] f[i][j][0] f[i][j][0]表示只考虑 a a a的前 i i i列,且第 i − 1 i-1 i−1列(从 0 0 0计数)涂 j j j个格子的情况下,且计入了 i i i列的下面的格子分数之后的最大得分(即计入 i − 2 i-2 i−2列对 i − 1 i-1 i−1列白色格子的分数贡献);而 f [ i ] [ j ] [ 1 ] f[i][j][1] f[i][j][1]表示不计入 i i i列的下面的格子分数的情况下的最大得分(即不计入贡献)。这样就好递推了:考虑 f [ i ] [ j ] f[i][j] f[i][j],我们也是枚举 i − 2 i-2 i−2列涂了 k k k个格子,
- 如果 k ≤ j k\le j k≤j,那么 i − 1 i-1 i−1列的下面的格子是无法算分的,所以 f [ i ] [ j ] [ 0 ] = f [ i ] [ j ] [ 1 ] f[i][j][0]=f[i][j][1] f[i][j][0]=f[i][j][1]。对于 i − 2 i-2 i−2列下面的被算分的格子,有两种情况,如果它是由其左边列贡献的,那么此时最大总分就是 f [ i − 1 ] [ k ] [ 0 ] f[i-1][k][0] f[i−1][k][0];如果它是由右边列贡献的,那么此时最大总分就是 f [ i − 1 ] [ k ] [ 1 ] + ∑ a [ . . . ] [ i − 2 ] f[i-1][k][1]+\sum a[...][i-2] f[i−1][k][1]+∑a[...][i−2]。
- 如果 k > j k>j k>j,那么 f [ i ] [ j ] [ 1 ] = f [ i − 1 ] [ k ] [ 0 ] f[i][j][1]=f[i-1][k][0] f[i][j][1]=f[i−1][k][0],而 f [ i ] [ j ] [ 0 ] = f [ i − 1 ] [ k ] [ 0 ] + ∑ a [ . . . ] [ i − 1 ] f[i][j][0]=f[i-1][k][0]+\sum a[...][i-1] f[i][j][0]=f[i−1][k][0]+∑a[...][i−1]。
最后答案即为 max k f [ n − 1 ] [ k ] [ 0 ] \max_k f[n-1][k][0] maxkf[n−1][k][0]。代码如下:
class Solution {
public:
using ll = long long;
ll maximumScore(vector<vector<int>>& g) {
int n = g.size();
ll f[n + 1][n + 1][2];
memset(f, 0, sizeof(f));
vector<vector<ll>> sum(n, vector<ll>(n + 1));
for (int i = 0; i < n; i++) {
sum[i][0] = 0;
for (int j = 1; j <= n; j++) sum[i][j] = sum[i][j - 1] + g[j - 1][i];
}
for (int i = 1; i < n; i++)
for (int j = 0; j <= n; j++) {
for (int k = 0; k <= j; k++) {
ll t = max(f[i - 1][k][0],
f[i - 1][k][1] + sum[i - 1][j] - sum[i - 1][k]);
f[i][j][0] = f[i][j][1] = max(f[i][j][0], t);
}
for (int k = j + 1; k <= n; k++) {
ll t = f[i - 1][k][0];
f[i][j][0] = max(f[i][j][0], t + sum[i][k] - sum[i][j]);
f[i][j][1] = max(f[i][j][1], t);
}
}
ll res = 0;
for (int j = 0; j <= n; j++) res = max(res, f[n - 1][j][0]);
return res;
}
};
时间复杂度 O ( n 3 ) O(n^3) O(n3),空间 O ( n 2 ) O(n^2) O(n2)。