揹包DP——混合揹包

uanQ發表於2024-06-29

顧名思義,混合揹包就是將前面三種的揹包問題(01,完全,多重)混合起來,有的只能取一次,有的能取無限次,有的只能取 k 次。

正解

特解

部分情況下,如小資料,可以轉換成多重揹包(把完全情況的數量換成足夠大,如1e7,就把完全相對變成了多重)

例題

https://www.luogu.com.cn/problem/P1833

櫻花

題目背景

《愛與愁的故事第四彈·plant》第一章。

題目描述

愛與愁大神後院裡種了 \(n\) 棵櫻花樹,每棵都有美學值 \(C_i(0 \le C_i \le 200)\)。愛與愁大神在每天上學前都會來賞花。愛與愁大神可是生物學霸,他懂得如何欣賞櫻花:一種櫻花樹看一遍過,一種櫻花樹最多看 \(P_i(0 \le P_i \le 100)\) 遍,一種櫻花樹可以看無數遍。但是看每棵櫻花樹都有一定的時間 \(T_i(0 \le T_i \le 100)\)。愛與愁大神離去上學的時間只剩下一小會兒了。求解看哪幾棵櫻花樹能使美學值最高且愛與愁大神能準時(或提早)去上學。

輸入格式

\(n+1\)行:

\(1\) 行:現在時間 \(T_s\)(幾時:幾分),去上學的時間 \(T_e\)(幾時:幾分),愛與愁大神院子裡有幾棵櫻花樹 \(n\)。這裡的 \(T_s\)\(T_e\) 格式為:hh:mm,其中 \(0 \leq hh \leq 23\)\(0 \leq mm \leq 59\),且 \(hh,mm,n\) 均為正整數。

\(2\) 行到第 \(n+1\) 行,每行三個正整數:看完第 \(i\) 棵樹的耗費時間 \(T_i\),第 \(i\) 棵樹的美學值 \(C_i\),看第 \(i\) 棵樹的次數 \(P_i\)\(P_i=0\) 表示無數次,\(P_i\) 是其他數字表示最多可看的次數 \(P_i\))。

輸出格式

只有一個整數,表示最大美學值。

樣例 #1

樣例輸入 #1

6:50 7:00 3
2 1 0
3 3 1
4 5 4

樣例輸出 #1

11

提示

\(100\%\) 資料:\(T_e-T_s \leq 1000\)(即開始時間距離結束時間不超過 \(1000\) 分鐘),\(n \leq 10000\)。保證 \(T_e,T_s\) 為同一天內的時間。

樣例解釋:賞第一棵櫻花樹一次,賞第三棵櫻花樹 \(2\) 次。

Code

點選檢視程式碼
const int maxn = 1e7 + 10;
int dp[maxn], w[maxn], v[maxn], sum[maxn];
int wnew[maxn], vnew[maxn];
pair<int, int> huan(string s) {
    int h, t;
    h = s[0] - '0';
    if (s.size() == 5) {
        h = h * 10 + s[1] - '0';
        t = (s[3] - '0') * 10 + s[4] - '0';
    }
    else { t = (s[2] - '0') * 10 + s[3] - '0'; }
    pair<int, int> p;
    p = {h, t};
    return p;
}
void solve() {
    int n, m;
    string s1, s2;
    cin >> s1 >> s2 >> n;
    auto [a1, b1] = huan(s1);
    auto [a2, b2] = huan(s2);
    m             = (a2 - a1) * 60 + b2 - b1;
    int cnt       = 0;
    for (int i = 1; i <= n; i++) {
        cin >> w[i] >> v[i] >> sum[i];
        int x = sum[i], j = 1;
        if (x == 0) x = maxn;
        while (x) {
            if (j <= x) {
                x -= j;
                wnew[++cnt] = w[i] * j;
                vnew[cnt]   = v[i] * j;
                j <<= 1;
            }
            else {
                wnew[++cnt] = w[i] * x;
                vnew[cnt]   = v[i] * x;
                break;
            }
        }
    }
    for (int i = 1; i <= cnt; i++) {
        for (int j = m; j >= wnew[i]; j--) {
            dp[j] = max(dp[j], dp[j - wnew[i]] + vnew[i]);
        }
    }

    cout << dp[m];
}

相關文章