读背包九讲心得

来源:互联网 发布:淘宝供销平台新玩法 编辑:程序博客网 时间:2024/05/17 03:04

一.01背包问题

01背包问题即物品有两种选择方式,拿或不拿,以nyoj289题为例:

苹果

时间限制:3000 ms | 内存限制:65535 KB
难度:2

描述
ctest有n个苹果,要将它放入容量为v的背包。给出第i个苹果的大小和价钱,求出能放入背包的苹果的总价钱最大值。

输入
有多组测试数据,每组测试数据第一行为2个正整数,分别代表苹果的个数n和背包的容量v,n、v同时为0时结束测试,此时不输出。接下来的n行,每行2个正整数,用空格隔开,分别代表苹果的大小c和价钱w。所有输入数字的范围大于等于0,小于等于1000。
输出
对每组测试数据输出一个整数,代表能放入背包的苹果的总价值。
样例输入
3 3
1 1
2 1
3 1
0 0
样例输出
2


思考:
这题就是典型的01背包问题,设weight[]表示苹果的大小(重量),value[]表示苹果的价钱(价值),背包的大小为v,苹果的个数为n。
那么设一个二维数组tab[i][j]表示在选择第i个苹果背包大小为j时的当前总最大价值,这里确实有点绕口,这里的思想就是把一个大的背包问题划分成小的背包的问题进行枚举;
帮助理解写一下伪代码:
for i=1:n
for j=v:0
tab[i][j]=max(tab[i-1][j], tab[i-1][j-weight[i]]+value[j])


max(tab[i-1][j], tab[i-1][j-weight[i]]+value[j])这句话得好好理解一下,tab[i][j]表示在选择第i个苹果背包大小为j时的当前总最大价值;那么在面对第i件物品时,不选择的话还是为tab[i-1][j],因为这时的价值为选择上一个物品的价值即i-1,因为没有选择i物品所以重量还是j,但是选择i件物品时就有 tab[i-1][j-weight[i]]+value[j],选择了第i件物品,那么的总价值即为i-1件物品的价值加上当前物品的价值,第i-1件物品的价值为tab[i-1][j],但是这时选择了物品i所以背包的大小便要减小,i物品的大小为weight[i],所以当前的大小为j-weight[i]。


这里写的java版本的,语言只是表达方式,核心代码也就那几句

/*** Title: e289 * Description: 苹果 * @author  * @date 2015年5月12日 下午10:17:03*/import java.util.Scanner;public class e289newD {    public static void main(String[] args) {        Scanner cin = new Scanner(System.in);        while (cin.hasNext()) {            int n = cin.nextInt(); // n个苹果            int size = cin.nextInt(); // 背包大小            if (n == size && n == 0) {                break;            }            int[] w = new int[n + 1];            int[] v = new int[n + 1];            for (int i = 1; i <= n; i++) {                w[i] = cin.nextInt();                v[i] = cin.nextInt();            }            solve(w, v, n, size);        }    }    private static void solve(int[] w, int[] v, int n, int size) {        int tab[][] = new int[n+1][size+1];        for (int i = 1; i <= n; i++) {            for (int j = size; j >0; j--) {                   int a = tab[i - 1][j];            if (j>=w[i]) {                int b = tab[i - 1][j - w[i]] + v[i];                tab[i][j] = max(a, b);            }else {                tab[i][j]=a;            }            }        }        System.out.println();        for (int i = 0; i < n+1; i++) {            for (int j = 0; j < size+1; j++) {                System.out.print(tab[i][j]+" ");            }            System.out.println();        }        System.out.println(tab[n][size]);    }    private static int max(int a, int b) {        return a > b ? a : b;    }}

打印结果如下:

3 31 12 13 10 0--0 0 0 0 0 1 1 1 0 1 1 2 0 1 1 2 2

如果想想到这里01背包就结束了总感觉有点不对,因为还有个东西在背包九讲上提到了,就是用一维数组就可以解决这个01背包问题设f[],这个f[]
就是当前每次循环时的状态简写

/*** Title: e289 * Description: 苹果 * @author  * @date 2015年5月12日 下午10:17:03*/import java.util.Scanner;public class e289 {    public static void main(String[] args) {        Scanner cin = new Scanner(System.in);        while (cin.hasNext()) {            int n = cin.nextInt(); //n个苹果            int size = cin.nextInt();   //背包大小            if (n == size && n == 0) {                break;            }            int[] w = new int[n+1];            int[] v = new int[n+1];            for (int i = 1; i <= n; i++) {                w[i] = cin.nextInt();                v[i] = cin.nextInt();            }            solve(w,v,n,size);        }    }    private static void solve(int[] w, int[] v, int n, int size) {        int f[]=new int[size+1];        for (int i = 1; i <= n; i++) {            for (int j = size; j >=w[i]; j--) {                f[j]=Math.max(f[j], f[j-w[i]]+v[i]);            }        }    System.out.println(f[size]);    }}

第二个for循环貌似有点不同,其实一开始我也直接按第二种写测,但是提交南阳不通过,我就改写了通过了,如果我知道我会再博客下方更新的。

0 0
原创粉丝点击