【Leetcode】3225. Maximum Score From Grid Operations

题目地址:

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 i1列(从 0 0 0计数)涂 j j j个格子的情况下,能得到的最大得分。我们枚举第 i − 2 i-2 i2列涂了多少个格子,假设涂 k k k个。如果 k > j k>j k>j,那么我们只需要在 f [ i − 1 ] [ k ] f[i-1][k] f[i1][k]基础上加上第 i i i列从 j j j k k k之间的白色格子的分数就行了;但是如果 k < j k<j k<j的话,我们无法判断 i − 1 i-1 i1列从 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 i1列(从 0 0 0计数)涂 j j j个格子的情况下,且计入了 i i i列的下面的格子分数之后的最大得分(即计入 i − 2 i-2 i2列对 i − 1 i-1 i1列白色格子的分数贡献);而 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 i2列涂了 k k k个格子,

  1. 如果 k ≤ j k\le j kj,那么 i − 1 i-1 i1列的下面的格子是无法算分的,所以 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 i2列下面的被算分的格子,有两种情况,如果它是由其左边列贡献的,那么此时最大总分就是 f [ i − 1 ] [ k ] [ 0 ] f[i-1][k][0] f[i1][k][0];如果它是由右边列贡献的,那么此时最大总分就是 f [ i − 1 ] [ k ] [ 1 ] + ∑ a [ . . . ] [ i − 2 ] f[i-1][k][1]+\sum a[...][i-2] f[i1][k][1]+a[...][i2]
  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[i1][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[i1][k][0]+a[...][i1]

最后答案即为 max ⁡ k f [ n − 1 ] [ k ] [ 0 ] \max_k f[n-1][k][0] maxkf[n1][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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值