Knapsack 背包问题
Knapsack 背包问题
0-1 Knapsack 单次选择,最大重量
��[�][�]=max��[�−1][�],��[�−1][�−�[�]+�[�]
class Solution {
public:
/**
* @param m: An integer m denotes the size of a backpack
* @param A: Given n items with size A[i]
* @return: The maximum size
*/
int backPack(int m, vector<int> &A) {
// write your code here
vector<int> dp(m+1,0);
for(int i=0; i<A.size(); i++){
for(int j=m; j>0; j--){
if(j>=A[i]){
dp[j]=max(dp[j], dp[j-A[i]]+A[i]);
}
else
dp[j]=dp[j];
}
}
return dp[m];
}
};
注意j的循环一定要倒着写,因为每次只能选择一次,只有倒着写可以引用到dp[i-1]的值。
0-1 Knapsack 2: 单次选择,最大价值
class Solution {
public:
/**
* @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
*/
int backPackII(int m, vector<int> &A, vector<int> &V) {
// write your code here
vector<int> dp(m+1,0);
for(int i=0; i<A.size(); i++)
for(int j=m; j>0; j--){
if(j>=A[i]){
dp[j]=max(dp[j], V[i]+dp[j-A[i]]);
}
}
return dp[m];
}
};
Unbounded Knapsack 3: 重复选择+最大价值
class Solution {
public:
/**
* @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
*/
int backPackII(int m, vector<int> &A, vector<int> &V) {
// write your code here
vector<int> dp(m+1,0);
for(int i=0; i<A.size(); i++)
for(int j=0; j<=m; j++){
if(j>=A[i]){
dp[j]=max(dp[j], V[i]+dp[j-A[i]]);
}
}
return dp[m];
}
};
这一回用正向遍历可以重复选择。
Unbounded Knapsack 4: 重复选择+唯一排列+装满可能性总数
这里我们的启发是,在背包问题dp数组中不一定非要存放什么价值阿,重量,也可以存放填满包的总方法数。
class Solution {
public:
/**
* @param nums: an integer array and all positive numbers, no duplicates
* @param target: An integer
* @return: An integer
*/
int backPackIV(vector<int> &nums, int target) {
vector<int> dp(target+1, 0);
dp[0]=1;
for(int i=0; i<nums.size(); i++)
for(int j=1; j<=target; j++){
if(nums[i]==j) dp[j]++;
else if(j > nums[i]) dp[j]+=dp[j-nums[i]];
}
return dp[target];
}
};
Unbounded Knapsack 5: 单次选择+装满可能性总数
class Solution {
public:
/**
* @param nums: an integer array and all positive numbers
* @param target: An integer
* @return: An integer
*/
int backPackV(vector<int> &nums, int target) {
vector<int> dp(target+1, 0);
dp[0]=1;
for(int i=0; i<nums.size(); i++)
for(int j=target; j>0; j--){
if(nums[i]==j) dp[j]++;
else if(j > nums[i]) dp[j]+=dp[j-nums[i]]; // or
// dp[j]+=dp[j-nums[i]]
}
return dp[target];
}
};
Unbounded Knapsack 6: Combination Sum IV 重复选择+不同排列+装满可能性总数
之前按元素顺序再按资源顺序慢慢选,这回相当于是全排列,先按资源来,这样可以引入全排列的杂乱性
换句话来讲, ��[�] 表示可以重复选择,资源j限制下的全排列数:
class Solution {
public:
/**
* @param nums: an integer array and all positive numbers, no duplicates
* @param target: An integer
* @return: An integer
*/
int backPackVI(vector<int> &nums, int target) {
vector<int> dp(target+1, 0);
dp[0]=1;
for(int j=1; j<=target; j++)
for(int i=0; i<nums.size(); i++){
if(nums[i]<=j) dp[j]+=dp[j-nums[i]];
}
return dp[target];
}
};
Bounded Knapsack 7 重复选择 有限次数 最大价值(多重背包问题)
Assume that you have n yuan. There are many kinds of rice in the supermarket. Each kind of rice is bagged and must be purchased in the whole bag. Given the weight, price and quantity of each type of rice, find the maximum weight of rice that you can purchase.
Example
Given:
n = 8
prices = [2,4]
weight = [100,100]
amounts = [4,2]
Return:400
显然可以转换成0-1动态规划问题 复杂度是�(�∗�∗∑�[�]) ,或者是重新把每个 �� 看成可以有 �� 的每个二进制位组成,降低复杂度到 �(�∗�∗∑log��)
Bounded Knapsack 8: 多重背包可行性解
Give some coins of different value and their quantity. Find how many values which are in range 1 ~ n can these coins be combined
n = 10
value = [1,2,4]
amount = [2,1,1]
Return: 8
They can combine all the values in 1 ~ 8
参考:
- https://segmentfault.com/a/1190000006325321
- https://en.wikipedia.org/wiki/Knapsack_problem#Definition
- https://www.kancloud.cn/kancloud/pa