zoukankan      html  css  js  c++  java
  • 集合角度DP分析

      动态规划(DP,Dynamic Programming)

    一、状态表示(f[i][j]表示什么?):

    1、集合:所有只考虑前 i 个物品,且总体积不超过 j 的选法的集合。

    2、属性:最大值(Max),还有最小值(Min),方案数。

    二、状态计算(f[i][j]怎么算出来?):

    1、所有不选第 i 个物品的方案:

    1 ~ i <= j, ------>>> 1 ~ i - 1 <= j,f[i - 1, j];

    2、所有选择第 i 个物品的方案:

    因为第 i 个物品必选,然后前 i - 1个物品任意选择。

    1 ~ i - 1 + i <= j,1 ~ i - 1 <= j - vi  ------>>> f[i - 1][j - vi] + w[i]

      然后在选 i 和不选 i 两种方案中取max :f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);

      DP优化:只是对代码做等价变形。

      优化方式:空间优化,二维优化成一维,f[j] = min(f[j], f[j - v[i]] + w[i]),然后第二层体积循环从大到小枚举:for(int j = V; j >= v[i]; j --),这样就可以保证在枚举 i 这一层物品的时候,f[j - v[i]]没有更新,用的还是上一层的 f[i - 1][j - v[i]]的体积。

      如果改成一维数组后第二层体积循环依然是从小到大枚举的话:for(int j = 0; j <= m; j ++),因为 f[j - v[i]]体积是枚举过的,在这一层得到更新,所以对应的一定是这一层 i 时候的 j - v[i] 即:f[i][j - v[i]]。

      f[j - v[i]] + w[i]取决于它是在第 i 层算出来的还是第 i - 1层算出来的,此时的f[j - v[i]]一定是第 i 层的。

    n = 4, V = 5,第1 - 4件物品的体积和价值分别是:
    1 2
    2 4
    3 4
    4 5

    体积

      编号

    0 1 2 3 4 5
    第0个物品 0 0 0 0 0 0
    第1个物品 0 2 2 2 2 2
    第2个物品 0 2 4 6 6 6
    第3个物品 0 2 4 6 6 8
    第4个物品 0 2 4 6 6 8
      for(int i = 1; i <= n; i ++)
            for(int j = 0; j <= m; j ++)
            {
                f[i][j] = f[i - 1][j];
                if(j >= v[i]) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
            }
    for(int i = 1; i <= n; i ++)
            for(int j = m; j >= v[i]; j --)
            {
                f[j] = max(f[j], f[j - v[i]] + w[i]);
            }

     二、完全背包问题

    
    
    for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++)
            {
                f[i][j] = f[i - 1][j];
                if(j >= v[i]) f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i]);
            }
    for(int i = 1; i <= n; i++)
           for(int j = v[i]; j <= m; j ++)
                f[j] = max(f[j], f[j - v[i]] + w[i]);

    三、石子合并

    #include <iostream>
    using namespace std;
    const int N = 310;
    int n, s[N], f[N][N];
    
    int main()
    {
        cin >> n;
        for(int i = 1; i <= n; i ++) cin >> s[i], s[i] += s[i - 1];
        
        for(int len = 2; len <= n; len ++)
            for(int i = 1; i + len - 1 <= n; i ++)
            {
                int j = i + len - 1;
                f[i][j] = 1e9;
                for(int k = i; k < j; k ++)
                    f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + s[j] - s[i - 1]);
            }
            
        cout << f[1][n] << endl;
    }

     四、最长公共子序列

    f[i][j] = max(f[i - 1][j - 1], f[i - 1][j], f[i][j - 1], f[i - 1][j - 1] + 1) ------>>>  f[i][j] = max(f[i - 1][j], f[i][j - 1], f[i - 1][j - 1] + 1) 

      for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++)
            {
                f[i][j] = max(f[i - 1][j], f[i][j - 1]);
                if(A[i] == B[j]) f[i][j] = max(f[i][j], f[i - 1][j - 1] + 1);
            }
  • 相关阅读:
    开机自动挂载分区
    Wine安装
    ubuntu 将idea/vscode快捷方式加入到启动器中
    在Linux上安装Java
    httpclient
    shiro
    redis-随笔
    maven
    spring的aop
    spring事务知识梳理
  • 原文地址:https://www.cnblogs.com/longxue1991/p/13356385.html
Copyright © 2011-2022 走看看