zoukankan      html  css  js  c++  java
  • 01背包裸题

    #include"cstdio"
    #include"cstring"
    #include"algorithm"
    using namespace std;
    int N,W;
    int w[105],p[105];
    int dp[10005];
    void DP()
    {
    
    for(int i=1; i<=N; i++)
    
            for(int c=W; c>=w[i]; c--)
    
                   dp[c] = max(dp[c],dp[c-w[i]]+p[i]);
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--){
        memset(dp,0,sizeof(dp));
        scanf("%d%d",&N,&W);
        for(int i=1;i<=N;i++)
        {
            scanf("%d%d",&w[i],&p[i]);
        }
        DP();
        printf("%d
    ",dp[W]);
        }
        return 0;
    }
    

     

    01背包的理解,二维数组化一维数组的理解(附hdu2602 Bone Collector)

    01背包问题:

    有n个物品和一个容量为v的背包,用val[i]表示第i个物品的价值,用vol[i]表示第i个物品的体积,那么,如何使背包里装的物品的总价值最大呢?

    贪心是不行的,举个反例:

    n=3, v=100

    val[i]vol[i]
    80 60
    50 50
    50 50

    按照val[i]/vol[i]比值从大到小贪心,那么会得到错误答案80,但是正确答案是100

    动态规划的思想:

    memset(dp, 0, sizeof(dp));
    for(int i=0; i<n; i++){
        for(int j=0; j<=v; j++){
        if(j>=vol[i])
            dp[i+1][j] = max(dp[i][j], dp[i][j-vol[i]]+val[i]);
            else
            dp[i+1][j] = dp[i][j];
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如何理解这段代码呢?我们设dp[i][j]为前i件物品放在容量为j的背包里所能得到的最大价值,那么思考一下,每个物品都只有两种可能,放或不放,这就是为什么叫做01背包的原因。那么,我们将第i件物品放在容量为j的背包中,使dp[i][j]最大,那么对于第i件物品,也只有两种操作。于是,我们可以很容易想到,我们不放第i件物品时,是不是需要先知道dp[i-1][j]的值呢?这就形成了dp,形成了一种递推关系。另一种可能,假设我们放第i件物品,那么,首先需要考虑当前容量j是否放得下物品i,假设放得下,将j减去vol[i],即在剩余的体积放前i件所得到的最大的价值为dp[i][j-vol[i]],所以总价值为dp[i][j-vol[i]] +val[i]。

    那么,状态转移方程为:

    dp[i+1][j] = max(dp[i][j], dp[i][j-vol[i]]+val[i])
    
    或者:
    dp[i][j] = max(dp[i-1][j], dp[i-1][j-vol[i]]+val[i])
    
    这两种写法要注意数组是从0开始还是从1开始
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    明显的,时间复杂度是O(n*v)

    但是我们还能将空间复杂度降低,从二维降为一维。

    看下面这段代码:

    memset(dp, 0, sizeof(dp));
    for(int i=0; i<n; i++){
        for(int j=v; j>=vol[i]; j--){
        dp[j] = max(dp[j], dp[j-vol[i]]+val[i])
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如何理解二维降一维呢?对于外层循环中的每一个i值,其实都是不需要记录的,在第i次循环时,所有的dp[0…v]都还未更新时,dp[j]还记录着前i-1个物品在容量为j时的最大价值,这样就相当于还记录着dp[i-1][j]和dp[i-1][j-vol[i]]+val[i]。

    为什么要从v开始递减遍历?我举个例子,假设一个物品GG价值1000,体积为2,那么假设我们按【0…..v】这个顺序遍历,那么在j=2时,dp[2] = max(dp[2], dp[0]+1000),那么dp[2] = 1000,当j=4时,dp[4]=max(dp[4], dp[2]+1000), dp[4] = 2000,这时我们再思考一下,GG将被放进背包两次!!,如果我们逆序遍历,就可以避免这种结果。

    此外,这里可以进行一个常数优化,将j>=vol[i]写进for循环中。

    大家可以看一下hdu2602这一题,是一题单纯的01背包。

    题目:

    Bone Collector

    Problem Description
    Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …
    The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?

    Input
    The first line contain a integer T , the number of cases.
    Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.

    Output
    One integer per line representing the maximum of the total value (this number will be less than 231).

    Sample Input
    1
    5 10
    1 2 3 4 5
    5 4 3 2 1

    Sample Output
    14

    用二维数组解:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    const int maxn = 1000+10;
    int val[maxn];
    int vol[maxn];
    int dp[maxn][maxn];
    
    int main(){
        int t, n, v;
        cin>>t;
        while(t--){
            cin>>n>>v;
            memset(vol, 0, sizeof(vol));
            memset(val, 0, sizeof(val));
            memset(dp, 0, sizeof(dp));
    
            for(int i=0; i<n; i++)
                cin>>val[i];
            for(int i=0; i<n; i++)
                cin>>vol[i];
    
            for(int i=0; i<n; i++){
                for(int j=0; j<=v; j++){
                    if(j>=vol[i])
                        dp[i+1][j] = max(dp[i][j], dp[i][j-vol[i]]+val[i]);
                    else
                        dp[i+1][j] = dp[i][j];
                }
            }
            cout<<dp[n][v]<<endl;
        }
        return 0;
    }
    • 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
    • 35
    • 36
    • 37

    用一维数组解:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    const int maxn = 1000+10;
    int val[maxn];
    int vol[maxn];
    int dp[maxn];
    
    int main(){
        int t, n, v;
        cin>>t;
        while(t--){
            cin>>n>>v;
            memset(vol, 0, sizeof(vol));
            memset(val, 0, sizeof(val));
            memset(dp,  0, sizeof(dp));
            for(int i=0; i<n; i++)
                cin>>val[i];
            for(int i=0; i<n; i++)
                cin>>vol[i];
    
            for(int i=0; i<n; i++){
                for(int j=v; j>=vol[i]; j--){
                    dp[j] = max(dp[j], dp[j-vol[i]]+val[i]);
                }
            }
            cout<<dp[v]<<endl;
        }
        return 0;
    }

     

  • 相关阅读:
    算法学习 -- 枚举
    一个简单程序的汇编执行过程分析
    计算思维(二) -- 符号化、计算化与自动化
    小记:vue 及 react 的工程项目入口小结及 webpack 配置多页面应用参考
    小记:iOS 中一般对于 view 不依赖 model 的的两种代码书写形式
    mac 下使用 ikbcG87 及使用 karabiner 改大小写键
    基于 svn 服务器及 cocoapods-repo-svn 插件进行组件化私有库的创建
    RxSwift 入坑好多天
    基于 socket.io, 简单实现多平台类似你猜我画 socket 数据传输
    基于 GCDAsyncSocket,简单实现类似《你猜我画》的 socket 数据传输
  • 原文地址:https://www.cnblogs.com/passion-sky/p/8997902.html
Copyright © 2011-2022 走看看