• 珍惜现在,感恩生活 (多重背包)


    题意;输入数据首先包含一个正整数C,表示有C组测试用例 每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100) 分别表示经费的金额和大米的种类,然后是m行数据,
    每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20) 分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。  求能得到的最大重量多重背包

    思路:这是一道很模板的多重背包

    所以我就对多重背包的dp思路总结一下:

    事实上多重背包问题可以看作0/1背包和完全背包的总和

    比如给出一个物品 体积w[i] , 数量num[i] , 如果 w[i]*num[i] >= N(总的背包体积/或者余下的体积),那么意味着 我可以随便取这个物品,直到背包装满 或者塞不下这个物品

    如果w[i]*num[i] <N ,那么我们就只能取(1~ num[i])个这个物品 ,我们假设其为 num[i]个不同的物品但是其w和v相同 ,然后一个一个取 (所以此时就转化为0/1背包)

    当然我们在一个一个取时可以相对优化一下 采用二进制的思想 更快速的取完这个物品

    下面这个代码是转用别人的模板我觉得对理解很有意义:https://blog.csdn.net/qq_38984851/article/details/81133840

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #define MAX 1000000
    using namespace std;
     
    int dp[MAX];//存储最后背包最大能存多少
    int value[MAX],weight[MAX],number[MAX];//分别存的是物品的价值,每一个的重量以及数量
    int bag;
     
    void ZeroOnePack(int weight,int value )//01背包
    {
        int i;
        for(i = bag; i>=weight; i--)
        {
            dp[i] = max(dp[i],dp[i-weight]+value);
        }
    }
    void CompletePack(int weight,int value)//完全背包
    {
        int i;
        for(i = weight; i<=bag; i++)
        {
            dp[i] = max(dp[i],dp[i-weight]+value);
        }
    }
     
    void MultiplePack(int weight,int value,int number)//多重背包
    {
        if(bag<=number*weight)//如果总容量比这个物品的容量要小,那么这个物品可以直到取完,相当于完全背包
        {
            CompletePack(weight,value);
            return ;
        }
        else//否则就将多重背包转化为01背包
        {
            int k = 1;
            while(k<=number)
            {
                ZeroOnePack(k*weight,k*value);
                number = number-k;
                k = 2*k;//这里采用二进制思想(二进制与十进制的转化)(快速幂也是这个思路)
                //而不是一个一个的减 
            }
            ZeroOnePack(number*weight,number*value);
        }
    }
    int main()
    {
        int t;
        cin>>t;
        while(t--){
             int n;
            while(~scanf("%d%d",&bag,&n))
            {
                int i,sum=0;
                for(i = 0; i<n; i++)
                {
                    scanf("%d",&weight[i]); 
                    
                    scanf("%d",&value[i]);//输入价值  此题没有物品的重量,可以理解为体积和价值相等
                       scanf("%d",&number[i]);//输入数量
                }
                memset(dp,0,sizeof(dp));
                for(i = 0; i<n; i++)
                {
                    MultiplePack(weight[i],value[i],number[i]);//调用多重背包,注意穿参的时候分别是
                    //重量,价值和数量
                }
                cout<<dp[bag]<<endl;
            }
            return 0;    
        }  
    }

    然后这是另一种思路的代码:(就是尝试对每一种都一个一个取)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int v[110],w[110],ans[110],dp[110][110];
    int main()
    {
        int t,n,m,i,j,k;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&m,&n); //m是经费,n种大米
            for(i=0;i<n;i++)
                scanf("%d%d%d",&w[i],&v[i],&ans[i]);//w价格,v是每袋的重量,ans是袋数
            memset(dp,0,sizeof(dp));  //初始化
            for(i=0;i<n;i++)   //n种大米
            {
                for(j=0;j<=m;j++)    //剩余j元最多能买多少
                {
                    if(j<w[i])        //剩余的钱不能买这一袋
                        dp[i+1][j]=dp[i][j];
                    else
                    {
                        for(k=0;k<=ans[i]&&w[i]*k<=j;k++)   //这种大米,从买0袋开始尝试买多少
                           dp[i+1][j]=max(dp[i+1][j],dp[i][j-k*w[i]]+k*v[i]);
                           //             原本的花费        这种大米买k袋
                    }
                }
            }
            printf("%d
    ",dp[n][m]);
        }
    
    }
  • 相关阅读:
    枚举enum
    C# 位运算符
    运算符&和&&以及|和||区别比较
    LINQ TO JSON
    LINQ 随机排序
    .NET Core LinQ
    CSharp笔记>>>多线程
    3D旋转
    CSharp 之CSkin的使用教程
    CSharp笔记>>>多语言,注册,模态对话框返回值
  • 原文地址:https://www.cnblogs.com/Tianwell/p/11218204.html
Copyright © 2020-2023  润新知