一、二维版本
dp[i][j]状态表示:前i个物品背包体积为j时的最大价值
void test_2_wei_bag_problem1() {
vector<int> weight = {1, 3, 4};
vector<int> value = {15, 20, 30};
int bagweight = 4;
// 二维数组
vector<vector<int>> dp(weight.size(), vector<int>(bagweight + 1, 0));
// 初始化
for (int j = weight[0]; j <= bagweight; j++) {
dp[0][j] = value[0];
}
// weight数组的大小 就是物品个数
for(int i = 1; i < weight.size(); i++) { // 遍历物品
for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
if (j < weight[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
cout << dp[weight.size() - 1][bagweight] << endl;
}
int main() {
test_2_wei_bag_problem1();
}
$时间复杂度O(n*m), 空间复杂度O(n*m)
go版本
func test_2_wei_bag_problem1(weight, value []int, bagweight int) int {
// 定义dp数组
dp := make([][]int, len(weight))
for i, _ := range dp {
dp[i] = make([]int, bagweight+1)
}
// 初始化
for j := bagweight; j >= weight[0]; j-- {
dp[0][j] = dp[0][j-weight[0]] + value[0]
}
// 递推公式
for i := 1; i < len(weight); i++ {
//正序,也可以倒序
for j := 0; j <= bagweight; j++ {
if j < weight[i] {
dp[i][j] = dp[i-1][j]
} else {
dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]]+value[i])
}
}
}
return dp[len(weight)-1][bagweight]
}
func max(a,b int) int {
if a > b {
return a
}
return b
}
func main() {
weight := []int{1,3,4}
value := []int{15,20,30}
test_2_wei_bag_problem1(weight,value,4)
}
$时间复杂度O(n*m), 空间复杂度O(n*m)
二、滚到数组版本
dp[i][j]状态表示:前i个物品背包体积为j时的最大价值
void test_1_wei_bag_problem() {
#define maxn 10010
vector<int> weight = {1, 3, 4};
vector<int> value = {15, 20, 30};
int dp[2][maxn];
int bagWeight = 4;
memset(dp, 0, sizeof dp);
// 初始化
for (int j = 0; j <= bagWeight; j++) {
dp[0][j] = j >= weight[0] ? value[0] : 0;
}
for(int i = 1; i < weight.size(); i++) { // 遍历物品
for(int j = 0; j <= bagWeight; j++) { // 遍历背包容量
int no = dp[i&1][j] = dp[(i-1)&1][j];
int yes = j >= weight[i] ? dp[(i-1)&1][j-weight[i]] + value[i]: 0;
dp[i&1][j] = max(no, yes);
}
}
cout << dp[(weight.size()-1)&1][bagWeight] << endl;
}
int main() {
test_1_wei_bag_problem();
}
$时间复杂度O(n*m), 空间复杂度O(m)
三、一维数组版本
dp[j]状态表示:前i个物品背包体积为j时的最大价值
void test_1_wei_bag_problem() {
vector<int> weight = {1, 3, 4};
vector<int> value = {15, 20, 30};
int bagWeight = 4;
// 初始化
vector<int> dp(bagWeight + 1, 0);
for(int i = 0; i < weight.size(); i++) { // 遍历物品
for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
cout << dp[bagWeight] << endl;
}
int main() {
test_1_wei_bag_problem();
}
$时间复杂度O(n*m), 空间复杂度O(m)
go版本
func test_1_wei_bag_problem(weight, value []int, bagWeight int) int {
// 定义 and 初始化
dp := make([]int,bagWeight+1)
// 递推顺序
for i := 0 ;i < len(weight) ; i++ {
// 这里必须倒序,区别二维,因为二维dp保存了i的状态
for j:= bagWeight; j >= weight[i] ; j-- {
// 递推公式
dp[j] = max(dp[j], dp[j-weight[i]]+value[i])
}
}
//fmt.Println(dp)
return dp[bagWeight]
}
func max(a,b int) int {
if a > b {
return a
}
return b
}
func main() {
weight := []int{1,3,4}
value := []int{15,20,30}
test_1_wei_bag_problem(weight,value,4)
}
$时间复杂度O(n*m), 空间复杂度O(m)
方法:01背包
dp[i][j]状态表示:前i个物品背包体积为j时的最大价值
class Solution {
#define maxn 20010
int dp[2][maxn];
public:
bool canPartition(vector<int>& nums) {
int sum = 0;
int i, j;
int n = nums.size();
for(i = 0; i < nums.size(); ++i) {
sum += nums[i];
}
if(sum & 1) {
return false;
}
sum /= 2;
//memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(i = 1; i <= nums.size(); ++i) {
int t = nums[i-1];
for(j = 0; j <= sum; ++j) {
int no = dp[i&1][j] = dp[(i-1)&1][j];
int yes = j >= t ? dp[(i-1)&1][j-t] : false;
dp[i&1][j] = no | yes;
}
}
return dp[n&1][sum];
}
};
$时间复杂度O(n*sum), 空间复杂度O(sum)
优化
class Solution {
#define maxn 10010
int dp[maxn];
public:
bool canPartition(vector<int>& nums) {
int sum = accumulate(nums.begin(), nums.end(), 0);
if (sum & 1) return false;
sum /= 2;
for (int i = 0; i < nums.size(); ++i) {
for (int j = sum; j >= nums[i]; --j) {
dp[j] = max(dp[j], dp[j-nums[i]] + nums[i]);
}
}
return dp[sum] == sum;
}
};
$时间复杂度O(n*sum), 空间复杂度O(sum)
优化:dp[i]能否恰好取到数的总和为i的情况
class Solution {
#define maxn 10010
bool dp[maxn];
public:
bool canPartition(vector<int>& nums) {
int sum = accumulate(nums.begin(), nums.end(), 0);
if (sum & 1) return false;
sum /= 2;
dp[0] = 1;
for (int i = 0; i < nums.size(); ++i) {
for (int j = sum; j >= nums[i]; --j) {
dp[j] |= dp[j-nums[i]];
}
}
return dp[sum];
}
};
$时间复杂度O(n*sum), 空间复杂度O(sum)