dp题单-背包问题

1、Cut Ribbon

思路一:数据范围很小,考虑直接枚举。

#include<bits/stdc++.h>
#define int long long
using namespace std;

int n, p, q, r;

signed main(){
    cin >> n >> p >> q >> r;
    int ans = 0;
    for(int i = 0; p * i <= n; i ++){
        for(int j = 0; p * i + q * j <= n; j++){//第二层for循环枚举的时候,要包含i的范围
            if((n - i * p - j * q) % r == 0){
                ans = max(ans, i + j + (n - i * p - j * q) / r);
            }
        }
    }
    cout << ans << endl;
    return 0;
}

思路二、考虑背包
完全背包(物品件数没有上限)。物品件数表示价值,长度表示体积。正常完全背包就可以。

2、Marvolo Gaunt's Ring

思路:每个位置上的数有两种状态,选或者不选,选了作为第几个数,作为第一个数?作为第二个数?作为第三个数?当前状态会与前一位的状态有关,考虑\(dp\)
\(dp[i][j]\):前\(i\)个数,选择\(j\)个时的最优解。当\(j = 0\)时,\(dp[i][0]\)表示\(ai \times p\)的最优解。\(j = 1,j = 2\)与之类似。

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N = 1e5 + 10;
int dp[N][3], a[N], n, p, q, r;

signed main(){
    cin >> n >> p >> q >> r;
    memset(dp, -0x3f, sizeof dp);
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }
    for(int i = 1; i <= n; i++){
        dp[i][0] = max(dp[i - 1][0], p * a[i]);
        dp[i][1] = max(dp[i][0] + a[i] * q, dp[i - 1][1]);//当j = 1时,要从dp[i][0]选
        dp[i][2] = max(dp[i][1] + a[i] * r, dp[i - 1][2]);
    }
    cout << dp[n][2] << endl;
    return 0;
}
3、Dima and Salad

image
小总结:遇到公式的时候,先对公式进行化简。
思路:把\(a_i - k \times b_i\)作为体积,价值为\(a_i\)。但是题目中的每个i对应的体积可能有正有负,这时候分别处理正负两种情况。我觉得这个地方是整道题思路最妙的地方。值得学习。
题解:https://www.luogu.com.cn/problem/solution/CF366C

4、Caesar's Legions

posted @ 2022-11-17 16:50  风归去  阅读(2)  评论(0编辑  收藏  举报