• 背包问题


      最近在洛谷上写了几个背包的板子题,总结一下。

      1. 01背包  

      01背包问题一般是:告诉你有N件物品和一个容量为V的背包。第i件物品的重量是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

      对于每一件物品我们可以选择取还是不取。

      我们可以定义一个二维数组 f[i][j] 来表示对前i个物品,你选择取或不取后,这个容量为V的背包中最大的价值为多少。

      对于第i个物品,当我们选择取的时候:f[i][j] = f[i-1][j-w[i]]+c[i] ;(显然此时 j 的范围为 w[i]~V )

      当我们选择不取的时候:f[i][j] = f[i-1][j];

      

    for(int i = 1; i <= N; i++)
        {
            for(int j = 0; j <= V; j++){
                if (V < w[i]){
                    f[i][j] = f[i-1][j];
                }else {
                    f[i][j] = max(f[i-1][j],f[i-1][j-w[i]]+c[i]);
                }
            }
        }

      显然,我们能把数组可以将f缩减成一维数组,从而达到优化空间的目的,状态转移方程转换为:

         f[j] = max(f[j],f[j-w[i]]+c[i])

    for(int i = 1; i <= N; i++)
        {
            for(int j = V; j >= w[i]; j--){
                f[j] = max(f[j],f[j-w[i]]+c[i]);
            }
        }

    例题:P2871 [USACO07DEC]手链Charm Bracelet

     

      2. 完全背包     

       完全背包问题一般是:告诉你有N种物品和一个容量为V的背包,每种物品不限数量。第i件物品的重量是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

      和01背包类似,我们对于每种物品可以不取、取一件、甚至取多件,只要容量够。

    for(int i = 1; i <= N; i++)
            for(int j=w[i]; j<=V; j++)
                f[j]=max(f[j-w[i]]+c[i], f[j]);

    例题:P2722 总分 Score Inflation

      3. 多重背包     

      多重背包问题一般是:告诉你有N种物品和一个容量为V的背包,每种物品数量为num[i]。第i件物品的重量是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

      我们可以把它转化为01背包问题。

      朴素算法:

    for (int i = 1; i <= N; i++)
            for (int j = V; j >= 0; j--)
                for (int k = 0; k <= num[i]; k++)
                {
                    if (j-k*w[i]<0) break;
                    f[j] = max(f[j],f[j-k*w[i]]+k*c[i]);
                }

      进行二进制优化:

      先将num[i]个物品分成多个物品,它们的重量方便为 c ={ k*c[i] | k = 1  2  4 8 ...,如果数量有剩余则剩下的算一个物体}

      然后按01背包做。

        int cnt = 0;
        for (int i = 0; i < N; i++){
            scanf("%d%d%d",&wi,&ci,&numi);
            for (int j = 1; j <= numi; j<<=1){
                w[cnt] = j*wi;
                c[cnt] = j*ci;
                numi-=j;
                cnt++;
            }
            if (numi){
                w[cnt] = numi*wi;
                c[cnt] = numi*ci;
                cnt++;
            }
        }
        for (int i = 0; i < cnt; i++){
            for (int j = V; j >= w[i]; j--){
                f[j] = max(f[j],f[j-w[i]]+c[i]);
            }
        }

      例题:51nod 1086背包问题v2

      

     

  • 相关阅读:
    hdu 5100 n*n棋盘放k*1长方条最多覆盖面积
    poj 3635/hdu 1676 Full Tank? 车辆加油+最短路
    poj 3613 经过k条边最短路 floyd+矩阵快速幂
    2014上海全国邀请赛 解题报告
    漫谈程序员系列:看看你离优秀有多远
    C2第七次作业解题报告
    C++ STL
    hdu 5098 双队列拓扑排序
    深度学习数据集 近百个开源数据集
    helper工具包——基于cifar10数据集的cnn分类模型的模块
  • 原文地址:https://www.cnblogs.com/l999q/p/9527957.html
Copyright © 2020-2023  润新知