• 三种背包模板


    零一背包倒着搜,完全背包正着搜,多重背包二进制存转化成01背包。

    0-1背包

    对于每种物品只有取与不取两个选择。

    洛谷p1048

    //https://www.luogu.com.cn/problem/P1048
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define ll long long
    const int maxn = 205;
    
    int cost[maxn];
    int val[maxn];
    int dp[105][maxn];        //dp[i][j]  当背包容积为j时,放入i的物品所获得的最大价值
    
    int main()
    {
        int t,m;
        scanf("%d%d",&t,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&cost[i],&val[i]);
        }
        for(int i=0;i<m;i++)
        dp[0][i]=0;
        for(int i=1;i<=m;i++)
            for(int j=t;j>=0;j--)
            {
                if(j>=cost[i])        //背包容积可以放下当前物品
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-cost[i]]+val[i]);
                else                  //放不下
                dp[i][j]=dp[i-1][j];
            }
        printf("%d
    ",dp[m][t]);
        return 0;
    }
    
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define ll long long
    const int maxn = 205;
    
    int cost[maxn];
    int val[maxn];
    int dp[1005];        //dp[j]  当背包容积为j时,所获得的最大价值
    
    int main()
    {
        int t,m;
        scanf("%d%d",&t,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&cost[i],&val[i]);
        }
        for(int i=0;i<m;i++)
        dp[i]=0;
        for(int i=1;i<=m;i++)          //滚动数组,依次遍历每个物品
            for(int j=t;j>=cost[i];j--) //当j小于cost[i]时,直接沿用原来的值  与二维 else dp[i][j]=dp[i-1][j];对应
            {
                dp[j]=max(dp[j],dp[j-cost[i]]+val[i]);
            }
        printf("%d
    ",dp[t]);
        return 0;
    }
    

    完全背包

    每种物品可以取无限多个。(在大部分情况下,用贪心思想,选性价比最高的物品其实就是答案,大概80%)。

    洛谷p2871

    //https://www.luogu.com.cn/problem/P2871
    //因数据范围问题,此代码无法ac,贴在这只是帮助理解
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define ll long long
    const int maxn = 205;
    
    int cost[maxn];
    int val[maxn];
    int dp[105][maxn];        //dp[i][j]  当背包容积为j时,可放入i种物品,所获得的最大价值
    
    int main()
    {
        int t,m;
        scanf("%d%d",&t,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&cost[i],&val[i]);
        }
        for(int i=0;i<m;i++)
        dp[0][i]=0;
        for(int i=1;i<=m;i++)
            for(int j=0;j<=t;j++)
            { 
                if(j>=cost[i]) //背包可以再放一个i类型的物品
                dp[i][j]=max(dp[i-1][j],dp[i][j-cost[i]]+val[i]);
                else  
                dp[i][j]=dp[i-1][j];
            }
        printf("%d
    ",dp[m][t]);
        return 0;
    }
    
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define ll long long
    const int maxn = 10000;
    
    int cost[maxn];
    int val[maxn];
    int dp[100000];        //dp[i][j]  当背包容积为j时,放入i的物品所获得的最大价值
    
    int main()
    {
        int t,m;
        scanf("%d%d",&t,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&cost[i],&val[i]);
        }
        for(int i=0;i<m;i++)
        dp[0]=0;
        for(int i=1;i<=m;i++)
            for(int j=cost[i];j<=t;j++)
            {
                dp[j]=max(dp[j],dp[j-cost[i]]+val[i]); //当j小于cost[i]时,直接沿用原来的值
            }
        printf("%d
    ",dp[t]);
        return 0;
    }
    

    多重背包

    每种物品限定了数量。

    可以把每一个都看成不同类型的物品,这样就转化成0-1背包问题了。

    但是直接转换会导致复杂度飙升,可以利用2进制来优化。

    以19为例子 它可以拆分(1+2+4+8+3),其实就是(2^0 + 2^1 + 2^2 + 2^3 +3)

    按照上面的划分,可以把19个同类型的背包拆分成5种不同类型的背包,比一个一个拆分要好得多。

    洛谷p1776

    //https://www.luogu.com.cn/problem/P1776
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define mem(a,b) memset(a,b,sizeof(a))
    #define ll long long
    const int maxn = 40005;
    
    int dp[maxn];
    int val[maxn<<2];
    int wei[maxn<<2];
    
    
    int main()
    {
        int n,mw;
        scanf("%d%d",&n,&mw); //种类  最大容积
        int v,w,m; //价值 重量 数量
        int cnt=1;
        for(int i=0;i<n;i++)
        {
            scanf("%d%d%d",&v,&w,&m);
            for(int j=1;j<=m;j<<=1)   //二进制优化
            {
                val[cnt]=v*j; wei[cnt]=w*j;
                m-=j; cnt++;
            }
            if(m) 
            {
                val[cnt]=v*m; wei[cnt]=w*m,cnt++;
            }
        }
        //for(int i=0;i<maxn;i++) dp[i]=0;
        for(int i=1;i<=cnt-1;i++)  //变成0-1背包问题
            for(int j=mw;j>=wei[i];j--)
            dp[j]=max(dp[j],dp[j-wei[i]]+val[i]);
        printf("%d
    ",dp[mw]);
        return 0;
    }
    
  • 相关阅读:
    回车符和换行符
    UDP ECHO server
    启动LINUX下的TFTP服务器
    WPF版的Dock控件第二版完成
    最近写的一个WPF版的Dock控件
    搜狗开始耍流氓了
    对WebBrowser控件设置代理
    删除Jumplist中的历史记录
    C#中Undo/Redo的一个简易实现
    如何向枚举中添加新值
  • 原文地址:https://www.cnblogs.com/chilkings/p/11988990.html
Copyright © 2020-2023  润新知