• 【志银】NYOJ《题目860》又见01背包


    题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=860

    方法一:不用滚动数组(方法二为用滚动数组,为方法一的简化)

    动态规划分析:最少要拿总价值一定,求所拿的最小质量(根据"最大能拿总重量一定,求能拿的最大价值"原理推导)

    (PS:为了更好的理解,先不用滚动数组,直接开了两个数组,第一个数组用来储存最少要拿总价值为j时所拿的最小质量,第二个数组用来储存第一个的改变前状态)
    例:
    最大总质量sw = 5,物品数量n = 4;
              1   2  3  4 <-第i个物品
    w[] = {2, 1, 3, 2} //重量
    v[] = {3, 2, 4, 2} //价值
    最大总质量sw = 5,最大总价值sv = 11,物品数量n = 4;

    分析打表结果如下:

     1 #include<iostream>
     2 using namespace std;
     3 int main() {
     4   int n, sw, sv, v[105], w[105], m[10005], b[10005];  //n为物品数量,sw为总重量,sv为总价值
     5   while(cin >> n >> sw) {      //m[j]为最少要拿总价值为j时所拿的最小质量
     6     sv = 0;                    //b[i]用来储存m[i]的上一个状态,如果用滚动数组方法就可以去掉b[]数组
     7     for(int i = 1; i <= n; i++) {
     8       cin >> w[i] >> v[i];
     9       sv += v[i];
    10     }
    11     for(int j = 1; j <= 10000; j++) {
    12       m[j] = 1000000001;  //初始化为题目范围内最大值
    13       b[j] = m[j];
    14     }
    15     m[0] = b[0] = 0;
    16     for(int i = 1; i <= n; i++) {
    17       for(int j = 1; j <= sv; j++) {
    18         if(j >= v[i]) m[j] = min(b[j], b[j-v[i]]+w[i]);
    19         else m[j] = min(b[j], w[i]);
    20       }
    21       for(int j = 0; j <= sv; j++) {
    22         b[j] = m[j];
    23         //b[j] > 1000000000 ? cout << "+ " : cout << b[j] << " ";    //去掉这两行注释可打表结果
    24       }
    25       //cout << endl;
    26     }
    27     int big = 1;  //从价值为1开始找所有能拿到的价值
    28     while(big <= sv && b[big] <= sw) big++;
    29     cout << big-1 << endl;
    30   }
    31 }
    代码实现(点击展开)

    方法二:用滚动数组(方法一的简化)

    原理:利用方法一的表格,按照价值j倒序计算表中的值

     1 #include<iostream>
     2 using namespace std;
     3 int main() {
     4   int n, sw, sv, v[105], w[105], m[10005];  //n为物品数量,sw为总重量,sv为总价值
     5   while(cin >> n >> sw) {      //m[j]为最少要拿总价值为j时所拿的最小质量
     6     sv = 0;
     7     for(int i = 1; i <= n; i++) { cin >> w[i] >> v[i]; sv += v[i]; }
     8     for(int j = 1; j <= 10000; j++) m[j] = 1000000001;  //初始化为题目范围内最大值
     9     for(int i = 1; i <= n; i++) {
    10       for(int j = sv; j >= 1; j--) {
    11         if(j >= v[i]) m[j] = min(m[j], m[j-v[i]]+w[i]);
    12         else m[j] = min(m[j], w[i]);
    13         //m[j] > 1000000000 ? cout << "+ " : cout << m[j] << " ";  //去掉这两行注释可打表结果
    14       }
    15       //cout << endl;
    16     }
    17     int big = 1;  //从价值为1开始找所有能拿到的价值
    18     while(big <= sv && m[big] <= sw) big++;
    19     cout << big-1 << endl;
    20   }
    21 }
    代码实现(点击展开)

                                                                                                                                开始写于:2016.5.20  ----志银

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    GithubPlus+PicGo + Typora 一键式图床
    快速掌握Linux这篇文章就够了。
    跨行程序员Java进阶--基础语法
    Prometheus(普罗米修斯)
    【学习记录】Golang
    服务器Docker-Compose 安装 Anaconda
    Kubernetes集群部署
    Jenkins部署
    Harbor部署
    Docker、Docker-Compose的安装以及相关使用
  • 原文地址:https://www.cnblogs.com/chenzhiyin/p/5513258.html
Copyright © 2020-2023  润新知