动态规划题目列表

做动态规划的题目之前养成手写dp的习惯,会避免很多问题

小明的背包(01背包)

https://www.lanqiao.cn/problems/1174/learning/?page=1&first_category_id=1&sort=students_count&problem_id=1174

  • 解释:一定要自己动手写一下dp,然后看一下怎么初始化的,然后再开始动手写代码,包括一维数组的实现为什么要倒叙j,因为会被覆盖掉
  • 二维数组代码:
    #include <iostream>
    using namespace std;
    
    int W[101];
    int V[101];
    int dp[101][1001];
    int N, C;
    
    int main()
    {
        // 请在此输入您的代码
        cin >> N >> C;
        for(int i = 0; i < N; i++) {
            cin >> W[i] >> V[i];
        }
        //初始化:
        //初始化列:
        for(int i = 0; i < N ;i++) {
            dp[i][0] = 0;
        }
        //初始化行:
        for(int i = 0; i <= C; i++) {
            if(W[0] <= i) {
                dp[0][i] = V[0];
            }else{
                dp[0][i] = 0;
            }
            
        }
    
        for(int i = 1; i < N; i++) {
            for(int j = 1; j <= C; j++) {
                if(W[i] > j) {
                    dp[i][j] = dp[i - 1][j];
                }else {
                    dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - W[i]] + V[i]);
                }
            }
        }
        cout << dp[N - 1][C];
        return 0;
    }
    
  • 一维数组代码:
    #include<iostream>
    #include<string.h>
    using namespace std;
    
    int N, C;
    int W[101];
    int V[101];
    int dp[1001];
    
    int main() {
        cin >> N >> C;
        memset(dp, 0, sizeof(dp));
        for(int i = 0; i < N; i++) {
            cin >> W[i] >> V[i];
        }
        for(int i = 0; i < N; i++) {
            // for(int j = 1; j <= C; j++) {
            //     //这里为什么不能从小到大循环呢?
            //     if(W[i] <= j) {
            //         dp[j] = max(dp[j], dp[j - W[i]] + V[i]);
            //         //..............如果从小到大,那么大的j - W[i]其实不是i - 1的时候的状态,而是被覆盖掉了
            //     }
            // }
            for(int j = C; j >= W[i]; j--) {
                dp[j] = max(dp[j], dp[j - W[i]] + V[i]);
            }
        }
        cout << dp[C];
        return 0;
    }
    
    
    

小明的背包2(完全背包)

https://www.lanqiao.cn/problems/1175/learning/?page=1&first_category_id=1&sort=students_count&name=小明的背包2

  • 解释: 还是一样的自己动手写一下dp表之后再做判断,先看二维的是怎么判断的
  • 二维数组代码:
    #include <iostream>
    using namespace std;
    
    int w[1001];
    int v[1001];
    int dp[1001][1001];
    int n, c;
    
    int main()
    {
        // 请在此输入您的代码
        cin >> n >> c;
        for(int i = 0; i < n; i++) {
            cin >> w[i] >> v[i];
        }
        //初始化第一列:
        for(int i = 0; i < n; i++) {
            dp[i][0] = 0;
        }
        //初始化第一行:
        for(int i = 0; i <= c; i++) {
            if(i >= w[0]) {
                dp[0][i] = i/w[0] * v[0];
            }else{
                dp[0][i] = 0;
            }
        }
        for(int i = 1; i < n; i++) {
            for(int j = 0; j <= c; j++) {
                if(w[i] > j) {
                    dp[i][j] = dp[i - 1][j];
                }else {
                    //到这里又要分两种情况,加还是不加,如果不加的话那就是dp[i - 1][j],也包含在下面的情况中;
                    for(int k = 0; k * w[i] <= j; k++){
                        dp[i][j] = max(dp[i][j], dp[i - 1][j - k*w[i]] + k*v[i]);
                    }
                }
            }
        }
        cout << dp[n - 1][c];
        return 0;
    }
    
  • 解释:一旦变成顺序的话就会导致每一个物品多加,所以可以加以区别
  • 一维代码:
    #include<iostream>
    #include<string.h>
    using namespace std;
    
    int w[1001];
    int v[1001];
    int dp[1001];
    int n, c;
    
    //你只要记住背包大小顺序的话就会导致多加就行了,那么完全背包就是顺序的
    
    int main() {
        cin >> n >> c;
        memset(dp, 0, sizeof(dp));
        for(int i = 0; i < n; i++) {
            cin >> w[i] >> v[i];
        }
        for(int i = 0; i < n; i++) {
            for(int j = 0; j <= c; j++) {
                if(w[i] <= j)
                dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
                
            }
        }
        cout << dp[c];
        return 0;
    }
    

2022

https://www.lanqiao.cn/problems/2186/learning/?page=1&first_category_id=1&sort=students_count&name=2022

  • 解释:很多的dp题目一开始的思考都是按照二维的来理解的,所以有的时候不要一味的追求一维实现而忽略二维的意义
  • 代码:
    #include<iostream>
    using namespace std;
    typedef long long ll;
    ll dp[2023][11][2023];
    int main() {
        //初始化:
        for(int i = 0; i <= 2022; i++) {
            dp[i][0][0] = 1;
        }
        for(int i = 1; i <= 2022; i++) {
            for(int j = 1; j <= 10; j++) {
                for(int k = 1; k <= 2022; k++) {
                    //两种情况,最后一位i有没有选择:
                    //第一种情况是i有选择
                    //dp[i - 1][j - 1][k - i];
                    //第二种情况,最后一位i没有选择
                    //dp[i - 1][j][k]
                    dp[i][j][k] = dp[i - 1][j][k] + (k >= i? dp[i - 1][j - 1][k - i] : 0);
                }
            }
        }
        cout << dp[2022][10][2022];
        return 0;
    }
    

数字三角形

https://www.lanqiao.cn/problems/505/learning/?page=1&first_category_id=1&sort=students_count&name=数字三角形

  • 代码
    #include<bits/stdc++.h>
    using namespace std;
    
    int n;
    int nums[101][101];
    int dp[101][101];
    
    int main()
    {
        cin >> n;
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < i + 1; j++) {
                cin >> nums[i][j];
            }
        }
        //初始化:
        dp[0][0] = nums[0][0];
        for(int i = 1; i < n; i++) {
            for(int j = 0; j < i + 1; j++) {
                //注意还要判断边界条件
                dp[i][j] = nums[i][j] + max((j - 1 >= 0 ? dp[i - 1][j - 1] : 0), (j <= i - 1 ? dp[i - 1][j] : 0));
            }
        }
        if(n%2 == 0) {
            cout << max(dp[n - 1][(n - 1)/2], dp[n - 1][(n - 1)/2 + 1]);
        }else {
            cout << dp[n - 1][n/2];
        }
        
        
       
        return 0;
    }
    
posted @ 2023-10-17 18:26  铜锣湾陈昊男  阅读(10)  评论(0)    收藏  举报