• 01背包问题


    问题描述
      给定N个物品,每个物品有一个重量W和一个价值V.你有一个能装M重量的背包.问怎么装使得所装价值最大.每个物品只有一个.
    输入格式
      输入的第一行包含两个整数n, m,分别表示物品的个数和背包能装重量。


      以后N行每行两个数Wi和Vi,表示物品的重量和价值
    输出格式
      输出1行,包含一个整数,表示最大价值。
    样例输入
    3 5
    2 3
    3 5
    4 7
    样例输出
    8
    数据规模和约定

      1<=N<=200,M<=5000.



    状态:
        f(i,j) 表示背包可用容量为j(1<=j<=w),已考虑物品 1,2,3, ... ,i(1<=i<=n) 时的最优解的值。
    状态方程:
        f(i,j)=f(i-1,j) j<w[i]时,物品i放不下
        f(i,j)=max{f(i-1,j) , f(i-1,j-w[i])+v[i]}    j>=w[i]时,在放入和不放入物品i之间选最优解
    边界条件:
        f(i,0)=0 背包不能装入任何物品,总价值为0
        f(0,j)=0 没有任何物品装入,总价值为0


    方法1:

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    int main()
    {
        int n,c;  //n是物品个数,c是背包容量
        cin>>n>>c;
        /*这里要注意数组申请空间是要多申请一个
        0号位赋值为0,这是为了在递推过程中f[][1]或f[1][]的值可正常推出
        */
        int *weight=new int[n+1];//重量
        int *value=new int[n+1]; //价值
    
        int **f=new int*[n+1];// f[i][j]表示在背包可用容量为j的情况下, 前i件宝贝的最大价值
        for(int i=0; i<=n; i++)
        {
            f[i]=new int[c+1];
        }
    
        for(int i=0; i<=n; i++)
            f[i][0]=0;
        for(int i=0; i<=c; i++)
            f[0][i]=0;
    
    
        for(int i=1; i<=n; i++)
        {
            cin>>weight[i]>>value[i];
        }
    
    /*
               | 0                              i=0 or w=0
        f[i,w]=| f[i-1,w]                       wi>w
               | max(vi+f[i-1,w-wi],f[i-1,w])   i>0 and w>=wi
    */
    
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=c; j++)
            {
                if(j<weight[i]) //背包装不下第i个物品,f[][]为前i-1件物品的最大价值
                    f[i][j]=f[i-1][j];  
                else            //背包可以装下第i个物品,如果放比不放价值大,则放
                    f[i][j]=max(f[i-1][j],f[i-1][j-weight[i]]+value[i]);  
            }
        }
        cout<<f[n][c]<<endl;
        return 0;
    }
    //这种方法空间利用率不高!!!


    方法2:(用一维数组实现)


    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    int main()
    {
        int n;//物品个数
        int c;//背包容量
    
        cin>>n>>c;
        int *weight=new int[n];//重量
        int *value=new int[n]; //价值
    
        for(int i=0; i<n; i++)
        {
            cin>>weight[i]>>value[i];
        }
    
        //数组多申请一个元素,容量从0~C,
        int dp[c+1];
        memset(dp,0,sizeof(dp));
    
        for(int i=0;i<n;i++)
        {
            for(int j=c;j>0;j--) //j为背包容量,其中容量为0时,价值势必为0,所以更新dp[]时,不用循环dp[0]
            {
                if(j>=weight[i])
                    dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
            }
        }
    
        cout<<dp[c]<<endl;
        return 0;
    }
    

    其中代码的第24~31行可以简化,如下:

        for(int i=0; i<n; i++)
        {
            for(int j=c; j>=weight[i]; j--) //j为背包容量,其中容量为0时,价值势必为0,所以更新dp[]时,不用循环dp[0]
            {
                dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
            }
        }


  • 相关阅读:
    关于程序与语言
    最新笔记请查看
    MySQL 性能优化
    k8s flannel无法跨主机ping通pod的解决方案
    k8s 使用kubeadm部署k8s集群初体验
    MySQL 锁和可重复读的隔离级别结合起来的一个示例(来自MySQL45讲第8章)
    MySQL 可重复读 vs 读提交
    Jenkins配置Linux节点,通过ssh方式在Linux节点自动拉取github代码并执行
    AppScan 使用
    Linux 动态链接库和静态库示例
  • 原文地址:https://www.cnblogs.com/zhanyeye/p/9746120.html
Copyright © 2020-2023  润新知