3 条题解

  • 9
    @ 2023-8-21 1:00:43

    这是一道经典的动态规划问题,使用状态转移方程求解。

    首先,我们定义一个二维数组 f,其中 f[i][j] 表示考虑前 i 个数,去掉 j 个数后,最多能有多少个数在正确位置上。

    接下来,使用两层循环遍历所有可能的状态。外层循环控制考虑的数的个数 i,从 1 到 n。内层循环控制去掉的数的个数 j,从 0 到 i

    在每个状态 (i, j) 下,有两种选择:

    1. 如果 i-1 大于等于 j,则可以选择将第 i 个数保留在正确位置上(即 a[i] == i - j),则 f[i][j] 的值为 f[i-1][j] 加上保留的数量。
    2. 如果 j 大于 0,则可以选择不保留第 i 个数,此时 f[i][j] 的值为 f[i-1][j-1]

    在每次选择后,更新 f[i][j] 的值为两种选择中较大的那个。

    最终,遍历所有状态 (n, j),找到最大的 f[n][j],即为擦除某些数后剩下的数列中最多能有多少个数在正确位置上。

    综上,状态转移方程如下: image

    其中,[a[i] = i-j] 是一个布尔值,表示第 i 个数是否在正确位置上。这里使用了一种简洁的写法,即当 a[i] = i-j 时,[a[i] = i-j] 的值为 1,否则为 0。

    根据状态转移方程,我们可以编写对应的代码实现。

    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main() {
        int n;
        cin >> n;
        vector<int> a(n + 1);
        for (int i = 1; i <= n; ++i) {
            cin >> a[i];
        }
    
        vector<vector<int>> f(n + 1, vector<int>(n + 1, 0));
        for (int i = 1; i <= n; ++i) {
            for (int j = 0; j <= i; ++j) {
                if (i - 1 >= j)
                    f[i][j] = max(f[i][j], f[i - 1][j] + (a[i] == i - j));
                if (j > 0)
                    f[i][j] = max(f[i][j], f[i - 1][j - 1]);
            }
        }
    
        int ans = 0;
        for (int i = 0; i <= n; ++i) {
            ans = max(ans, f[n][i]);
        }
    
        cout << ans << endl;
    
        return 0;
    }
    
    
  • 1
    @ 2024-5-6 21:09:14

    这是一道动态规划问题。

    首先,我们定义一个二维数组 ff[i][j] 表示考虑前 i 个数,去掉 j 个数后,最多能有多少个数在正确位置上。

    接下来,用两层循环遍历所有可能的状态。外层循环控制考虑的数的个数 i,从 1 到 n内层循环控制去掉的数的个数 j,从 0 到 i

    每个状态 (i, j) 下,有两种选择:

    1. 如果 i-1 大于等于 j,则可以选择将第 i 个数保留在正确位置上(即 a[i] == i - j),f[i][j] 的值为 f[i-1][j] 加上保留的数量。
    2. 如果 j 大于 0,则可以选择不保留第 i 个数,此时 f[i][j] 的值为 f[i-1][j-1]

    每次选择后,都更新 f[i][j] 的值为两种选择中最大的那个。

    最终,遍历所有状态 (n, j),找到最大的 f[n][j],即为擦除某些数后剩下的数列中最多能有多少个数在正确位置上。

    状态转移方程如下: image

    编写循环时可用f[i][j]去表示考虑前i个数,**去掉j个数后,最多有多少个数在正确位置上。**前i个数去掉j个后,a[i]就在第i-j个位置上,如果a[i]等于i-j,说明它在正确位置上。 代码如下:

    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main() 
    {
        int n;
        cin >> n;
        vector<int> a(n + 1);
        for (int i = 1; i <= n; ++i) {
            cin >> a[i];
        }
    
        vector<vector<int>> f(n + 1, vector<int>(n + 1, 0));
        for (int i = 1; i <= n; ++i) {
            for (int j = 0; j <= i; ++j) {
                if (i - 1 >= j)
                    f[i][j] = max(f[i][j], f[i - 1][j] + (a[i] == i - j));
                if (j > 0)
                    f[i][j] = max(f[i][j], f[i - 1][j - 1]);
            }
        }
    
        int ans = 0;
        for (int i = 0; i <= n; ++i) {
            ans = max(ans, f[n][i]);
        }
    
        cout << ans << endl;
    
        return 0;
    }
    
    
    

    代码按课程里编写代码的话,思路代码都是这样的。 照课里面讲的和书里的做很简单。

    • 1
      @ 2023-8-20 18:32:00

      可以用f[i][j]表示考虑前i个数,去掉j个数后,最多能有多少个数在正确位置上。前i个数去掉j个后,a[i]数在第i-j个位置上,如果a[i]等于i-j,说明它在正确位置上。状态转移方程见代码。

      核心代码
      
      for (int i = 1; i <= n; i++) {
          for (int j = 0; j <= i; j++) {
              if (i - 1 >= j)
                  f[i][j] = max(f[i][j], f[i - 1][j] + (a[i] == i - j));
              if (j > 0)
                  f[i][j] = max(f[i][j], f[i - 1][j - 1]);
          }
      }
      for (int i = 0; i <= n; i++)
          ans = max(ans, f[n][i]);
      
      • 1

      信息

      ID
      380
      时间
      1000ms
      内存
      256MiB
      难度
      2
      标签
      (无)
      递交数
      349
      已通过
      222
      上传者