其他分享
首页 > 其他分享> > 【洛谷 P1833 樱花】解题报告(多重背包)

【洛谷 P1833 樱花】解题报告(多重背包)

作者:互联网

题意简述

\(n\) 种物品,每种物品有代价 \(T_i\)、权值 \(C_i\) 和个数 \(A_i\)(若 \(A_i=0\) 表示有无穷多个),最多代价为 \(m\),权值和最大为多少。

\(1\le m\le 10^3\),\(1\le n\le 10^4\)。

题解

首先,时间 HH1:MM1~HH2:MM2 的跨度非常好算,这里就不说了,假设为 \(m\)。

由于 \(m\le 10^3\) 且 \(T_i > 0\),显然每种物品不可能被选择超过 \(10^3\) 次,因此如果 \(A_i=0\) 可以直接赋值 \(A_i\gets 10^3\),同时对于所有 \(A_i\) 进行 \(A_i\gets\min\{A_i,10^3\}\)。

然后本题转化为多重背包问题,直接二进制拆分后跑 0/1 背包即可。

参考代码

//By: Luogu@rui_er(122461)
#include <bits/stdc++.h>
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
#define debug printf("Running %s on line %d...\n",__FUNCTION__,__LINE__)
using namespace std;
typedef long long ll;
const int N = 2e5+5, M = 1005, inf = 1000;

int HH1, MM1, HH2, MM2, n, m, a[N], b[N], c[N], cost[N], v[N], tot, dp[M];
template<typename T> void chkmin(T &x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T &x, T y) {if(x < y) x = y;}

int main() {
    scanf("%d:%d %d:%d %d", &HH1, &MM1, &HH2, &MM2, &n);
    m = (HH2 - HH1) * 60 + MM2 - MM1;
    rep(i, 1, n) {
        scanf("%d%d%d", &a[i], &b[i], &c[i]);
        if(!c[i]) c[i] = inf;
        chkmin(c[i], inf);
        rep(j, 0, 10) {
            if(c[i] < (1 << j)) break;
            cost[++tot] = a[i] * (1 << j);
            v[tot] = b[i] * (1 << j);
            c[i] -= 1 << j;
        }
        if(c[i]) {
            cost[++tot] = a[i] * c[i];
            v[tot] = b[i] * c[i];
        }
    }
//  rep(i, 1, tot) printf("%d %d\n", cost[i], v[i]);
    rep(i, 1, tot) per(j, m, cost[i]) chkmax(dp[j], dp[j-cost[i]]+v[i]);
    printf("%d\n", dp[m]);
    return 0;
}

标签:__,10,le,洛谷,HH2,MM1,MM2,P1833,解题
来源: https://www.cnblogs.com/ruierqwq/p/LG-P1833.html