zoukankan      html  css  js  c++  java
  • B

    Given a set of n items, each with a weight w[i] and a value v[i], determine a way to choose the items into a knapsack so that the total weight is less than or equal to a given limit B and the total value is as large as possible. Find the maximum total value. (Note that each item can be only chosen once).

    Input

    The first line contains the integer T indicating to the number of test cases.

    For each test case, the first line contains the integers n and B.

    Following n lines provide the information of each item.

    The i-th line contains the weight w[i] and the value v[i] of the i-th item respectively.

    1 <= number of test cases <= 100

    1 <= n <= 500

    1 <= B, w[i] <= 1000000000

    1 <= v[1]+v[2]+...+v[n] <= 5000

    All the inputs are integers.

    Output

    For each test case, output the maximum value.

    Sample Input

    1
    5 15
    12 4
    2 2
    1 1
    4 10
    1 2

    Sample Output

    15

    自己找了两个背包的代码敲了上去,第一个因为重复查找的次数太多TEL, 第二个因为数组空间开的太大爆了。

    TEL代码

     1 int n, W;
     2 int w[MAX_N], v[MAX_N];
     3 
     4 int rec(int i, int j) {
     5     int res;
     6     if (i == n) {
     7         res = 0;
     8     } else if (j < w[i]) {
     9         res = rec(i + 1, j);
    10     } else {
    11         res = max(rec(i + 1, j), rec(i + 1, j - w[i]) + v[i]);
    12     }
    13     return res;
    14 }
    15 
    16 void solve() {
    17     printf("%d
    ", rec(0, W));
    18 }

    上面的代码可以优化,试产殉国的位置不再进行查询,但是要开一的dp[MAX_N][MAX_W]的数组,因为MAX_W的取值范围太大所以这种方法不能够用来解答此题。

    优化代码

     1 int dp[MAX_N][MAX_W];
     2 
     3 int rec(int i, int j) {
     4     if (dp[i][j] >= 0) 
     5         return dp[i][j];
     6     
     7     int res;
     8     if (i == n) {
     9         res = 0; 
    10     } else if (j < w[i]) {
    11         res = rec(i+1, j);
    12     } else {
    13         res = max(rec(i+1, j), rec(i+1, j-w[i]) + v[i]);
    14     }
    15     return dp[i][j] = res;
    16 }
    17 
    18 void solve() {
    19     memset(dp, -1, sizeof(dp));
    20     printf("%d
    ", rec(0, W));
    21 }

    超大背包,因为此题的背包数量太多,用超大背包的话算法复杂度是O(2^n)级别,所以此题也不能用超大别抱来解决。超大背包只适合用来解决别博爱的数量很少但是重量和价值都很大的情况。

    超大背包代码:

     1 typedef long long ll;
     2 
     3 int n;
     4 ll w[MAX_N], v[MAX_N];
     5 ll W;
     6 
     7 pair<ll, ll> ps[1 << (MAX_N / 2)];
     8 
     9 void solve() {
    10     int n2 = n / 2;
    11     for (int i = 0; i < 1 << n2; i++) {
    12         ll sw = 0, sv = 0;
    13         for (int j = 0; j < n2; j++) {
    14             if (i >> j & 1) {
    15                 sw += w[j];
    16                 sv += v[j];
    17             }
    18         }
    19         ps[i] = make_pair(sw, sv);
    20     }
    21     
    22     sort(ps, ps + (1 << n2));
    23     int m = 1;
    24     for (int i = 1; i < 1 << n2; i++) {
    25         if (ps[m-1].second < ps[i].second) {
    26             ps[m++] = ps[i];
    27         }
    28     }
    29     
    30     ll res = 0;
    31     for (int i = 0; i < 1 << (n-n2); i++) {
    32         ll sw = 0, sv = 0;
    33         for (int j = 0; j < n - n2; j++) {
    34             if (i >> j & 1) {
    35                 sw += w[n2+j];
    36                 sv += v[n2+j];
    37             }
    38         }
    39         if (sw <= W) {
    40             ll tv = (lower_bound(ps, ps+m, make_pair(W - sw, INF)) - 1) -> second;
    41             res = max(res, sv + tv);
    42         }
    43     }
    44     printf("%d
    ", res);
    45 }

    题解:

    最大质量为1000000000,数组肯定不够用。

    不过,总价值才5000,我们以价值为轴开辟记录剩余可载质量的一维数组,后面的做法就与01背包如出一辙。

    AC代码

     1 #include<cstdio>
     2 #include<cstring>
     3 int main(){
     4     int weight[5001], t, i, j, n, B, max_value, w, v;
     5     scanf("%d", &t);
     6 
     7     while (t--){
     8         scanf("%d%d", &n, &B);
     9         memset(weight, 0, sizeof(weight));
    10         weight[0] = B, max_value = 0;
    11 
    12         for (j = 0; j < n; ++j){
    13             scanf("%d%d", &w, &v);
    14             for (i = max_value; i >= 0; --i){
    15                 if (weight[i] - w > weight[i + v]) weight[i + v] = weight[i] - w;
    16             }
    17             for (i = max_value + 1; i <= 5000; ++i) if (weight[i]) max_value = i;
    18         }
    19 
    20         printf("%d
    ", max_value);
    21     }
    22     return 0;
    23 }

    总结:通过这题也让我明白了自己对摸板代码的理解程度还远远不够,所以才会出现这样的情况。

    加油!!!!!!!!!!

    永远渴望,大智若愚(stay hungry, stay foolish)
  • 相关阅读:
    面试题-JAVA算法题
    分布式
    linux中文件描述符fd和struct file结构体的释放
    Linux字符设备驱动
    Linux内存地址管理概述
    mnist卷积网络实现
    【TensorFlow官方文档】MNIST机器学习入门
    FCN笔记
    datetime.timedelta
    tensorflow中的函数获取Tensor维度的两种方法:
  • 原文地址:https://www.cnblogs.com/h-hkai/p/8908416.html
Copyright © 2011-2022 走看看