洛谷P1757 通天之分组背包 题解提供4种做法

:需先预习01背包再做此题



P1757 通天之分组背包:传送门

题目大意:物品大致可分为 k 组,每组中的物品相互冲突(每组只能用一个),求最大使用价值。

方法一:二维数组

定义数组w[k][i]表示第k组第i个的重量,数组v[k][i]表示第k组第i个的价值,数组f[j]表示目前用j个价值的最优解。

动态规划转移方程:f[j] = max(f[j],f[j-w[k][i]+v[k][i])

代码如下:

#include<bits/stdc++.h>
using namespace std;
int w[110][1100],v[110][1100],f[11000];
int main(){
    int m,n,maxxx = 0;
    cin >> m >> n;
    for(int i = 1;i <= n;i++){
        int a,b,c;
        cin >>a>>b>>c;
        w[c][++w[c][0]] = a;
        v[c][++v[c][0]] = b;
        maxxx = max(maxxx,c);//打擂台求最大组数
    }
    for (int k = 1; k <= maxxx; k++){//枚举组数
        for(int j = m;j >= 0;j--){//从大到小防止重复
            for(int i = 1;i <= w[k][0];i++){//枚举第k组的第i个数
                if(j >= w[k][i]){
                    f[j]= max(f[j],f[j-w[k][i]]+v[k][i]);
                }
            }
        }
    }
    cout << f[m];//结果存到了f[m]里
    return 0;
}

​

方法二:结构体

使用结构体的有点就是一目了然,十分清楚。具体看代码。

#include<bits/stdc++.h>
using namespace std;
int dp[1001];
struct stu{
    int as[1000],b[1000],x;//as[z]表示该项第z项的物品重量,b[z]表示该项第z项的物品价值,x表示该项有x个元素。
}a[300];
int main(){
    int m,n,cmax = -1;
    cin >> m >> n;
    for(int i = 1;i <= n;i++){
        int aa,bb,cc;
        cin >> aa>> bb>> cc;
        a[cc].x+= 1;
        a[cc].as[a[cc].x] = aa,a[cc].b[a[cc].x] = bb;
        cmax = max(cmax,cc);//打擂台求最大值。
    }
    for(int i = 1;i <= cmax;i++){
        for(int j = m;j >= 1;j--){
            for(int z = 1;z <= a[i].x;z++){
                if(j < a[i].as[z]) continue;
                dp[j] = max(dp[j],dp[j-a[i].as[z]]+a[i].b[z]);
            }
        }
    }
    cout << dp[m];
    return 0;
}

方法三:一维数组解

#include<bits/stdc++.h>
using namespace std;
int dp[1001],aa[1001],bb[1001],cc[1001],lsh[1001],lh = 0,c[1001],id[1004][1004],len[1001];
int main(){
    int m,n,cmax = -1;
    cin >> m >> n;
    for(int i = 1;i <= n;i++){
        cin >> aa[i]>> bb[i]>> cc[i];
        lsh[++lh] = cc[i];
    }
    sort(lsh+1,lsh+lh+1);//用sort排序(为了偷懒)
    lh = unique(1+lsh,lsh+lh+1)-lsh-1;//去重后得到的长度
    for(int i = 1;i <= n;i++){
        int rd = lower_bound(lsh+1,lsh+lh+1,cc[i])-lsh;//二分查找cc[i]的位置,更快。
        c[i] = rd;
        cmax = max(cmax,rd);
    }
    for(int i = 1;i <= n;i++){
        id[c[i]][++len[c[i]]] = i;
    }
    for(int i = 1;i <= cmax;i++){
        for(int j = m;j >= 1;j--){
            for(int z = 1;z <= len[i];z++){

                int t = id[i][z];
                if(j < aa[t])continue;
                dp[j] = max(dp[j],dp[j-aa[t]]+bb[t]);
            }
        }
    }
    cout << dp[m];
    return 0;
}

方法四:map解

#include<bits/stdc++.h>
using namespace std;
int dp[1001],aa[1001],bb[1001],cc[1001],lsh[1001],lh = 0,c[1001],id[1004][1004],len[1001];
map <int,int> mp;
int main(){
    int m,n,cmax = -1;
    cin >> m >> n;
    for(int i = 1;i <= n;i++){
        cin >> aa[i]>> bb[i]>> cc[i];
        if(mp[cc[i]] == 0) mp[cc[i]] = ++lh;
        c[i] = mp[cc[i]];
    }
    for(int i = 1;i <= n;i++){
        id[c[i]][++len[c[i]]] = i;
    }
    for(int i = 1;i <= lh;i++){
        for(int j = m;j >= 1;j--){
            for(int z = 1;z <= len[i];z++){

                int t = id[i][z];
                if(j < aa[t])continue;
                dp[j] = max(dp[j],dp[j-aa[t]]+bb[t]);
            }
        }
    }
    cout << dp[m];
    return 0;
}

最后总结一下

不得不说,这其实就是01背包精华版!!(题目有间接表明)需掌握01背包

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值