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;
}
}