背包型动态规划

92. Backpack

可行性

https://www.lintcode.com/problem/backpack/description?_from=ladder&&fromId=16

public class Solution {
    /**
     * @param m: An integer m denotes the size of a backpack
     * @param A: Given n items with size A[i]
     * @return: The maximum size
     */
    public int backPack(int m, int[] A) {
        // write your code here
        int n = A.length;
        if(n==0){
            return 0;
        }
        //前i个物品拼出j的重量
        boolean[][] f = new boolean[n+1][m+1];

        for(int i =1;i<=m;i++){
            f[0][i]= false;
        }

        f[0][0]= true;
        for(int i=1;i<=n;i++){
            for(int w =0;w<=m;w++){
                f[i][w] = f[i-1][w];

                if(w>=A[i-1]){
                    f[i][w]=(f[i][w] || f[i-1][w-A[i-1]]);
                }
            }
        }

        for(int i = m;i>=0;i--){
            if(f[n][i]){
                return i;
            }
        }

        return 0;
    }
}

滚动数组优化版:

public class Solution {
    /**
     * @param m: An integer m denotes the size of a backpack
     * @param A: Given n items with size A[i]
     * @return: The maximum size
     */
    public int backPack(int m, int[] A) {
        // write your code here
        int n = A.length;
        if(n==0){
            return 0;
        }
        //前i个物品拼出j的重量
        boolean[][] f = new boolean[n+1][m+1];

        int old =0;
        int now =0;

        for(int i =1;i<=m;i++){
            f[now][i]= false;
        }

        f[now][0]= true;
        for(int i=1;i<=n;i++){
            old = now;
            now = 1-now;
            for(int w =0;w<=m;w++){
                f[now][w] = f[old][w];

                if(w>=A[i-1]){
                    f[now][w]=(f[now][w] || f[old][w-A[i-1]]);
                }
            }
        }

        for(int i = m;i>=0;i--){
            if(f[now][i]){
                return i;
            }
        }

        return 0;
    }
}

正整数求和可考虑背包问题

563. Backpack V

计数型

https://www.lintcode.com/problem/backpack-v/?_from=ladder&&fromId=16

public class Solution {
    /**
     * @param nums: an integer array and all positive numbers
     * @param target: An integer
     * @return: An integer
     */
    //f[i][w] = f[i-1][w]+f[i-1][w-A[j]]
    //初始条件:f[0][0] = 1
    // f[0][1...m] = 0;
    public int backPackV(int[] nums, int target) {
        // write your code here
        if(nums==null || nums.length==0){
            return 0;
        }
        int n = nums.length;

        int[][] f = new int[n+1][target+1];

        for(int i=1;i<=target;i++){
            f[0][i] =0;
        }

        f[0][0] = 1;

        for(int i =1;i<=n;i++){
            for(int w =0;w<=target;w++){
                f[i][w]= f[i-1][w];
                if(w>=nums[i-1]){
                    f[i][w]+=f[i-1][w-nums[i-1]];
                }
            }
        }

        return f[n][target];

    }
}

空间优化成一维滚动数组

public class Solution {
    /**
     * @param nums: an integer array and all positive numbers
     * @param target: An integer
     * @return: An integer
     */
    //f[i][w] = f[i-1][w]+f[i-1][w-A[j]]
    //初始条件:f[0][0] = 1
    // f[0][1...m] = 0;
    public int backPackV(int[] nums, int target) {
        // write your code here
        if(nums==null || nums.length==0){
            return 0;
        }
        int n = nums.length;

        int[] f = new int[target+1];

        for(int i=1;i<=target;i++){
            f[i] =0;
        }

        f[0] = 1;

        for(int i =1;i<=n;i++){
            //right -> left
            for(int w =target;w>=nums[i-1];w--){
                    f[w]+=f[w-nums[i-1]]; //overwrit

            }
        }

        return f[target];

    }
}

564. Combination Sum IV

计数型

https://www.lintcode.com/problem/combination-sum-iv/description?_from=ladder&&fromId=16

public class Solution {
    /**
     * @param nums: an integer array and all positive numbers, no duplicates
     * @param target: An integer
     * @return: An integer
     */
    public int backPackVI(int[] nums, int target) {
        // write your code here
        if(nums==null || nums.length==0){
            return 0;
        }

        if(target==0){
            return 0;
        }

        int[] f = new int[target+1];
        f[0]=1;

        for(int i =1;i<=target;i++){
            for(int j=0;j<nums.length;j++){
                if(i>=nums[j])
                    f[i]+=f[i-nums[j]];
            }
        }

        return f[target];

    }
}

125. Backpack II

最值型

https://www.lintcode.com/problem/backpack-ii/description?_from=ladder&&fromId=16

public class Solution {
    /**
     * @param m: An integer m denotes the size of a backpack
     * @param A: Given n items with size A[i]
     * @param V: Given n items with value V[i]
     * @return: The maximum value
     */
    public int backPackII(int m, int[] A, int[] V) {
        // write your code here
        if(A==null || A.length==0 || V==null || V.length ==0){
            return 0;
        }

        int n = A.length;

        int[][] f = new int[n+1][m+1];
        f[0][0] = 0;

        for(int i =1;i<=m;i++){
            f[0][i] = -1;
        }

        for(int i=1;i<=n;i++){
            for(int w=0;w<=m;w++){
                f[i][w] = f[i-1][w];
                if(w>=A[i-1] && f[i-1][w-A[i-1]]!=-1){
                    f[i][w] = Math.max(f[i][w],f[i-1][w-A[i-1]]+V[i-1]);
                }
            }
        }

        int res = 0;
        for(int i =0;i<=m;i++){
            res = Math.max(res,f[n][i]);
        }

        return res;
    }
}

440. Backpack III

最值型

https://www.lintcode.com/problem/backpack-iii/description?_from=ladder&&fromId=16

思路:由Backpack II扩展出来,设k为i-1物体取用次数

public class Solution {
    /**
     * @param A: an integer array
     * @param V: an integer array
     * @param m: An integer
     * @return: an array
     */
    public int backPackIII(int[] A, int[] V, int m) {
        // write your code here
        if(A==null || A.length==0 || V==null || V.length==0){
            return 0;
        }

        int n = A.length;

        int[][]f = new int[n+1][m+1];

        f[0][0] = 0;

        for(int i=1;i<=m;i++){
            f[0][i]=-1;
        }

        for(int i=1;i<=n;i++){
            for(int w=0;w<=m;w++){
                f[i][w] = f[i-1][w];
                int currW = w;
                int k =1;
                while(currW>=A[i-1]){
                    if(f[i-1][currW-A[i-1]]!=-1){
                        f[i][w] = Math.max(f[i][w],f[i-1][currW-A[i-1]]+V[i-1]*k);
                    }
                    currW-=A[i-1];
                    k++;
                }
            }
        }

        int res = 0;
        for(int i=1;i<=m;i++){
            res = Math.max(res,f[n][i]);
        }

        return res;
    }
}

优化1:观察公式,进行简化

优化思路,其实最后一个无论取几次,都相当于k-1次取值f[i][w-A[i-1]]+V[i-1];

public class Solution {
    /**
     * @param A: an integer array
     * @param V: an integer array
     * @param m: An integer
     * @return: an array
     */
    public int backPackIII(int[] A, int[] V, int m) {
        // write your code here
        if(A==null || A.length==0 || V==null || V.length==0){
            return 0;
        }

        int n = A.length;

        int[][]f = new int[n+1][m+1];

        f[0][0] = 0;

        for(int i=1;i<=m;i++){
            f[0][i]=-1;
        }

        for(int i=1;i<=n;i++){
            for(int w=0;w<=m;w++){
                f[i][w] = f[i-1][w];
                //优化思路,其实最后一个无论取几次,都相当于k-1次取值f[i][w-A[i-1]]+V[i-1];
                if(w>=A[i-1] && f[i][w-A[i-1]]!=-1){
                    f[i][w] = Math.max(f[i][w],f[i][w-A[i-1]]+V[i-1]);
                }
            }
        }

        int res = 0;
        for(int i=1;i<=m;i++){
            res = Math.max(res,f[n][i]);
        }

        return res;
    }
}

优化2:画图之后改成一维滚动数组

public class Solution {
    /**
     * @param A: an integer array
     * @param V: an integer array
     * @param m: An integer
     * @return: an array
     */
    public int backPackIII(int[] A, int[] V, int m) {
        // write your code here
        if(A==null || A.length==0 || V==null || V.length==0){
            return 0;
        }

        int n = A.length;

        int[]f = new int[m+1];

        f[0] = 0;

        for(int i=1;i<=m;i++){
            f[i]=-1;
        }

        for(int i=1;i<=n;i++){
            for(int w=0;w<=m;w++){
                //优化思路,其实最后一个无论取几次,都相当于k-1次取值f[i][w-A[i-1]]+V[i-1];
                if(w>=A[i-1] && f[w-A[i-1]]!=-1){
                    f[w] = Math.max(f[w],f[w-A[i-1]]+V[i-1]);
                }
            }
        }

        int res = 0;
        for(int i=1;i<=m;i++){
            res = Math.max(res,f[i]);
        }

        return res;
    }
}

原文地址:https://www.cnblogs.com/lizzyluvcoding/p/10798998.html

时间: 2024-08-29 23:26:15

背包型动态规划的相关文章

采药---0-1背包型dp

题目描述 Description 辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他出了一个难题.医师把他带到一个到处都是草药的山洞里对他说:"孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值.我会给你一段时间,在这段时间里,你可以采到一些草药.如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大." 如果你是辰辰,你能完成这个任务吗? 输入描述 Input Descriptio

树型动态规划练习总结

类型一.多叉树转二叉树进行资源分配 例如: * 例1. 选课:每门课可能有一门先选课,即某些课必须在另外的某节课被选之后才能选,每门课能得的学分不同,求最大学分. * 例2. 通向自由的钥匙:可以从一个房间通向另外多个房间,通过每个房间所需的花费不同,得到的价值也不同,用最小花费获得最大价值. 这种题目的特点是需要在多叉树上进行资源的分配,对不同的子树分配不同的资源,以求最大价值.可以直接在多叉树上用背包的方式求解,但是更常用的方法是用左孩子右兄弟表示法转化为二叉树. 转化之后的通用状态转移方程

Codevs_2102_石子归并2_(划分型动态规划)

描述 http://codevs.cn/problem/2102/ 与Codevs_1048_石子归并_(划分型动态规划)相比,现在是环状的,起点任意. 2102 石子归并 2 时间限制: 10 s 空间限制: 256000 KB 题目等级 : 黄金 Gold 题目描述 Description 在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分.试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最

nyist oj 311 完全背包 (动态规划经典题)

完全背包 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 直接说题意,完全背包定义有N种物品和一个容量为V的背包,每种物品都有无限件可用.第i种物品的体积是c,价值是w.求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大.本题要求是背包恰好装满背包时,求出最大价值总和是多少.如果不能恰好装满背包,输出NO 输入 第一行: N 表示有多少组测试数据(N<7). 接下来每组测试数据的第一行有两个整数M,V. M表示物品种类的数目,V表示背包的总容

区间型动态规划的记忆化搜索实现与环形动态规划的循环数组实现

区间型动态规划的典型例题是石子归并,同时使用记忆化搜索实现区间动归是一种比较容易实现的方式,避免了循环数组实现的时候一些边界的判断 n堆石子排列成一条线,我们可以将相邻的两堆石子进行合并,合并之后需要消耗的代价为这两堆石子的质量之和,问最小的合并代价 状态转移方程很容易给出: f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[i][j]) 因为要计算区间和,考虑前缀和进行预处理 然后我们给出用记忆化搜索形式实现的代码,这里的记忆化搜索形式可以作为后续问题的一个模

nyist oj 311 全然背包 (动态规划经典题)

全然背包 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描写叙述 直接说题意,全然背包定义有N种物品和一个容量为V的背包.每种物品都有无限件可用.第i种物品的体积是c,价值是w. 求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大.本题要求是背包恰好装满背包时,求出最大价值总和是多少. 假设不能恰好装满背包,输出NO 输入 第一行: N 表示有多少组測试数据(N<7). 接下来每组測试数据的第一行有两个整数M.V. M表示物品种类的数目,V表示背

01背包和动态规划

做了一段时间NOI,做到动态规划看了几天算法书籍.还是没有深入,学了基本的动态规划,稍有一点体会,记录到这里. 背包是这样一类问题:在限定总质量前提下,从若干质量\价格对中,取哪些能使得价格最大. 动态规划是一种思想,简单的说,动态规划思想就是充分利用对子问题的计算结果来递推父问题结果.所以,动态规划具有较高的效率,省去了一些不必要的计算.这里主要关心表和递推关系,其实这两者是同一个东西,根据记录表来推得父问题的解,找到递推关系要依赖表记录子问题的解.不同的问题有不同的构建方式,所以我个人觉得,

代码与算法集锦-归并排序+树状数组+快排+深度优先搜索+01背包(动态规划)

归并排序 求逆序数 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 首先考虑下如何将将二个有序数列合并.这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数.然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可. //将有序数组a[]和b[]合并到c[]中 void MemeryArray(int a[], int n, int b[], int m, int c

POJ 1155 TELE 背包型树形DP 经典题

由电视台,中转站,和用户的电视组成的体系刚好是一棵树 n个节点,编号分别为1~n,1是电视台中心,2~n-m是中转站,n-m+1~n是用户,1为root 现在节点1准备转播一场比赛,已知从一个节点传送数据到达另一个节点,电视台需要一定的费用 若可以传送数据到达用户的节点n-m+1~n,这些用户各自愿意支付一定的费用给电视台 现在电视台希望在不亏本的情况下为尽量多的用户转播比赛 输出最多可以为多少用户转播比赛 背包类型的树形DP第一题 dp[i][j]表示以节点i为根的子树有j个用户获得转播,电视