背包问题

背包例题归纳

分组背包

通常采用的方法是 dp[i][j] 是前 i 堆物品里取 j 次

基德的金币挑战

地址

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
void solve()
{
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i][0];
        for(int j=1;j<=a[i][0];j++){
            cin>>a[i][j];
            pr[i][j]=pr[i][j-1]+a[i][j];
        }
    }
    //dp[i][j]表示前i堆金币中取j次的最大价值
    for(int i=1;i<=n;i++){
        for(int j=0;j<=k;j++){
            for(int num=0;num<=min(j,a[i][0]);num++){//本次取num个
                dp[i][j]=max(dp[i][j],dp[i-1][j-num]+pr[i][num]);
            }
        }
    }
    cout<<dp[n][k]<<"\n";
}

小红升装备

地址

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void solve()
{
    int n,x;
    cin>>n>>x;
    vector<int> w,v;
    vector<vector<PII>> h(n);
    while(n--){
        int i1,c1,i2,c2,mx;
        cin>>i1>>c1>>i2>>c2>>mx;
        // 每次升级是一个新的物品
        for(int i=0;i<=mx;i++){
            int va=i1+i*c2;
            int we=c1+i2*i;
            if(we>x) break;
            h[n].push_back({we,va});
        }
    }

    // 分组背包,每一组最多选一个
    n=h.size();
    vector<int> dp(x+1,0);
    for(int i=0;i<n;i++){
        auto f=dp;
        for(int j=0;j<h[i].size();j++){
            auto [we,va]=h[i][j];
            for(int k=x;k>=we;k--){
                f[k]=max(f[k],dp[k-we]+va);
                // 需要注意这里的写法,保证这一层的最大值由上一层转移而来,并与这一层比较
            }
        }
        dp=f;
    }
    cout<<*max_element(dp.begin(),dp.end())<<'\n';
}
Licensed under CC BY-NC-SA 4.0
最后更新于 Apr 18, 2024 00:00 UTC
本博客已稳定运行
使用 Hugo 构建
主题 StackJimmy 设计