zoukankan      html  css  js  c++  java
  • 0-1背包问题复习

    准备面试,通过做POJ上的题,复习算法知识,做POJ 3624复习了背包相关知识。

    背包九讲时有些实现细节不是很懂,于是就从最直接的实现开始实现0-1背包的动态规划算法,再逐渐写出优化后的解法。
    状态转移方程便是:
    f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

    直接写出两层循环下的代码,N代表物品的数量,M表示最大背包能放下的最大容积,w[i]表示第i个物品的重量,d[i]表示第i个物品的价值。a[i][j]表示前i个物品放入容量为 j 的背包中获得的最大收益。

    for (int i = 1; i <= N ; i ++) {
     for (int j = 0; j <= M ; j ++) {
      if (j - w [i ] >= 0) {
          a[i][j] = Math.max(a[i-1][j],a[i-1][j-w [i]] + d[i]);
       } else{
          a[i][j] = a[i-1][j];
           }
        }
     }

    再写出空间优化后的代码,也就是内层循环倒写的写法,f[j]相当于之前的f[i][j]

    for (int i = 1; i <= N; i++) {
         for (int j = M; j >= 0; j--) {
        if (j - w[i] >= 0) {
            f[j] = Math.max(f[j], f[j - w[i]] + d[i]);
        }
    }

    对比两个写法,有几点需要注意:

    1. 第一个写法中的内层循环可以递增也可以递减,第二个则必须递减,递减写法保证第i次循环结束后f[v]中表示的就是我们定义的状态f[i][v],f[i][v]是由f[i-1][v]和f[i-1][v-c[i]]两个子问题递推而来,j的值递减保证在推f[i][v]时(也即在第i次主循环中推f[v]时)能够得到f[i-1][v]和f[i-1][v-c[i]]的值
    2. 第一个写法要加else,第二个不用加else。第二个写法中如果if不成立,f[j]不变,相当于第一个写法中将a[i][j] = a[i-1][j]。
    3. 第一个中的i值必须从1开始,第二个的i值则不要求。
    package PackProblem;
    
    import java.util.Scanner;
    
    /**
     * O-1背包,数组长度有误,要开到14000才AC.
     * 5412K,2532MS
     * @author DaiSong
     * @Date 2014年3月2日
     */
    public class Poj_3624 {
    
        static int f[] = new int[15000];
    
        public static int ZeroOnePack(int d[], int w[], int n, int m) {
    
             for(int i = 0; i < n; i++) {
                for (int j = m; j >= 0; j--) {
                    if (j - w[i] >= 0) {
                        f[j] = Math.max(f[j], f[j - w[i]] + d[i]);
                    }
                }
                for (int j = 0; j <= m; j++) {
                    System.out.print(f[j] + " ");
                }
                System.out.println();
            }
            return f[m];
        }
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int n, m;
            int d[] = new int[15000];
            int w[] = new int[15000];
            n = sc.nextInt();
            m = sc.nextInt();
            for (int i = 0; i < n; i++) {
                w[i] = sc.nextInt();
                d[i] = sc.nextInt();
            }
            System.out.println(ZeroOnePack(d, w, n, m));
        }
    }

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    C# DataTable 和List之间相互转换的方法
    毫秒级百万数据分页存储过程(mssql)
    lambdas vs. method groups
    关于优化C#程序的五十种方法
    Retrieving failed records after an SqlBulkCopy exception
    将数字按照3位一组添加逗号的正则替换
    生成互不相同随机数的一种算法
    2018年ElasticSearch6.2.2教程ELK搭建日志采集分析系统(教程详情)
    2018年ElasticSearch6.2.2教程ELK搭建日志采集分析系统(目录)
    JMeter接口压力测试课程入门到高级实战
  • 原文地址:https://www.cnblogs.com/AndyDai/p/4734086.html
Copyright © 2011-2022 走看看