完全背包

440. 背包问题 III

给定 n 种物品, 每种物品都有无限个. 第 i 个物品的体积为 A[i], 价值为 V[i].

再给定一个容量为 m 的背包. 问可以装入背包的最大价值是多少?

样例
样例 1:

输入: A = [2, 3, 5, 7], V = [1, 5, 2, 4], m = 10
输出: 15
解释: 装入三个物品 1 (A[1] = 3, V[1] = 5), 总价值 15.
样例 2:

输入: A = [1, 2, 3], V = [1, 2, 3], m = 5
输出: 5
解释: 策略不唯一. 比如, 装入五个物品 0 (A[0] = 1, V[0] = 1).
注意事项
不能将一个物品分成小块.
放入背包的物品的总大小不能超过 m.

一个普通的完全背包问题

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
        
        int n = A.length;
        
        int[][] a = new int[n+1][m+1];
        
        for (int i = 1; i < n+1 ; i++ ){
            for (int j = 1; j < m+1; j++){
                int k = j / A[i-1];
                for (int s = 0; s < k+1; s++ ){
                    if(j >= s * A[i-1]){
                        a[i][j] = Math.max(a[i][j], a[i-1][j-s*A[i-1]] + s*V[i-1]);
                    }
                } 
            } 
        }
        
        return a[n][m];
        
    }
    
}

562. 背包问题 IV

给出 n 个物品, 以及一个数组, nums[i]代表第i个物品的大小, 保证大小均为正数并且没有重复, 正整数 target 表示背包的大小, 找到能填满背包的方案数。
每一个物品可以使用无数次

样例
样例1

输入: nums = [2,3,6,7] 和 target = 7
输出: 2
解释:
方案有:
[7]
[2, 2, 3]
样例2

输入: nums = [2,3,4,5] 和 target = 7
输出: 3
解释:
方案有:
[2, 5]
[3, 4]
[2, 2, 3]

public class Solution {
    /**
     * @param nums: an integer array and all positive numbers, no duplicates
     * @param target: An integer
     * @return: An integer
     * a[i][j]为前i个物品填满容量为j的背包方案数
     * a[i][j] += a[i-1][j-k*nums[i-1]];表示第i个物品放k个产生的
     * 方案数
     * a[0][0]=1表示0个物品填满容量为0的背包的方案为1个
     */
    public int backPackIV(int[] nums, int target) {
        // write your code here
        int m = target;
        int n = nums.length;
        
        int [][]a = new int[n+1][m+1];
        a[0][0] = 1;
        // for (int i = 0; i < n + 1; i++) {
        //     a[i][0] = 1;
        // }

        for (int i = 1; i < n+1; i++) {
            for (int j = 0; j < m+1; j++){
                int s = j / nums[i-1];
                
                for(int k = 0; k < s+1; k++){
                    if(j >= k * nums[i-1]){
                        a[i][j] += a[i-1][j-k*nums[i-1]];
                    }
                    
                }
            }
        }
        
        return a[n][m];
    }
}

800. 背包问题 IX

你总共有n 万元,希望申请国外的大学,要申请的话需要交一定的申请费用,给出每个大学的申请费用以及你得到这个大学offer的成功概率,大学的数量是 m。如果经济条件允许,你可以申请多所大学。找到获得至少一份工作的最高可能性

样例
样例 1:
输入:
n = 10
prices = [4,4,5]
probability = [0.1,0.2,0.3]
输出: 0.440

解释:
选择第2和第3个学校。

样例 2:
输入:
n = 10
prices = [4,5,6]
probability = [0.1,0.2,0.3]
输出: 0.370

解释:
选择第1和第3个学校。

注意事项
0<=n<=10000,0<=m<=10000

逆向思考
还要注意事件同时发生的概率是乘的

/*
    算法武器:背包DP

思想:反向思考(对问题做等价变换)
对于概率类问题,如果题目要求我们求一件事情成功的最大概率p,我们可以将其转化为求一件事情失败的最小概率p',那么,1 - p'就是我们所求问题的答案。

分析:背包大小为总钱数,物品大小为各大学申请费,物品价值为大学录取率
状态:dp[i][j]申请前i个学校花费不超过j的一所没中的最小概率 => 一所没中的概率最小 => 中至少一所概率最大
转移方程:dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - prices[i - 1]] * (1 - probability[i - 1])
初始条件:
dp[0][j] = 1 => 一所大学不申请,肯定中不上
dp[i][0] = 1, i != 0 => 申请至少一所大学不花钱,不可能
答案:1 - dp[m][n]
    */
public class Solution {
    /**
     * @param n: Your money
     * @param prices: Cost of each university application
     * @param probability: Probability of getting the University's offer
     * @return: the  highest probability
     */
    public double backpackIX(int m, int[] prices, double[] probability) {
        // write your code here
        int n = prices.length;
        double [][] a = new double[n+1][m+1];
        
        for (int i = 0; i < n+1 ;i++  ){
            a[i][0] = 1;
        }
        for (int j = 0; j < m+1; j++){
            a[0][j] = 1;
        }
        
        for (int i = 1; i<n+1 ;i++ ){
            for(int j = 0; j < m+1; j++){
                if(j < prices[i-1]){
                    a[i][j] = a[i-1][j];
                    continue;
                }
                a[i][j] = Math.min(a[i-1][j], a[i-1][j-prices[i-1]] *(1.0-probability[i-1]));
            }
        } 
        
        double res = 1.0 - a[n][m];
        return res;
    }
}

801. 背包问题X

你总共有n元,商人总共有三种商品,它们的价格分别是150元,250元,350元,三种商品的数量可以认为是无限多的,购买完商品以后需要将剩下的钱给商人作为小费,求最少需要给商人多少小费

样例
样例 1:

输入: n = 900
输出: 0
样例 2:

输入: n = 800
输出: 0

还是反向思考,自己花的最多,剩下的就最少

public class Solution {
    /**
     * @param n: the money you have
     * @return: the minimum money you have to give
     */
    public int backPackX(int m) {
        // write your code here
        int []A = {0, 150, 250, 350};
        int n = 3;
        
        int [][]a = new int[n+1][m+1];
        
        for (int i = 1; i<n+1; i++ ){
            for (int j = 0; j<m+1; j++ ){
                int s = j / A[i];
                for (int k = 0; k<s+1; k++ ){
                    if(j >= k*A[i]){
                        a[i][j] = Math.max(a[i][j], a[i-1][j-k*A[i]] + k*A[i]);
                    }
                } 
            } 
        }
        int res = m - a[n][m];
        return res;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值