背包问题——基础(C/C++)

01背包问题

  • 原题链接
  • 题解
    对选择物品的循环直接从讨论第一个物品拿或不拿开始
    所以在循环中<=n<=m都是很重要的
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1010;

int v[maxn];//体积
int w[maxn];//价值
int f[maxn][maxn];

int main() {
    
    int n, m;
    
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];
    for (int i = 1; i <= n; i++)
        for (int j = 0; j <= m; j++) {
            f[i][j] = f[i - 1][j]; //不选第i号物品
            if(j >= v[i])
                f[i][j] = max(f[i][j], f[i - 1][j - v[i]] +w[i]); //选第i号物品
        }
    int ans = 0;
    for (int j = 0; j <= m; j++)
        ans = max(ans, f[n][j]);
    cout << ans << endl;
    return 0;
}

完全背包问题

1.三重循环的做法,时间复杂度比较高,循环过程比较具现化一点,相比起01背包问题中只考虑拿或不拿的思路,完全背包需要考虑对第i个物品拿0个,1个,2个…等情况。因此加入第三个循环while(j>k*v[i])代替01背包中的判断语句if(j>v[i])。导致时间复杂度到了n的三次方,面对比较复杂的数据容易超时。

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1010;

int v[maxn];//体积
int w[maxn];//价值
int f[maxn][maxn];

int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];
    for (int i = 1; i <= n; i++)
        for (int j = 0; j <= m; j++) {
            f[i][j] = f[i - 1][j]; //不选第i号物品
            int k = 1;
            while (j >= k * v[i]) {
                f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]); //选第i号物品k个
                k++;
            }
        }
    int ans = 0;
    for (int j = 0; j <= m; j++)
    ans = max(ans, f[n][j]);
    cout << ans << endl;
    return 0;
}

2.优化:f[i - 1][j - k * v[i]] + k * w[i],i取1,2,3…(满足j>k*v[i]皆可),其实就是f[i][j-v[i]] + w[i]

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1010;

int v[maxn];//体积
int w[maxn];//价值
int f[maxn][maxn];

int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];
    for (int i = 1; i <= n; i++)
        for (int j = 0; j <= m; j++) {
            f[i][j] = f[i - 1][j];   //不选第i号物品
            if(j>=v[i])
                f[i][j] = max(f[i][j], f[i][j -v[i]] + w[i]); 
        }
    int ans = 0;
    for (int j = 0; j <= m; j++)
    ans = max(ans, f[n][j]);
    cout << ans << endl;
    return 0;
}

[中等]零钱兑换

  • 原题链接
  • 题解
    基于完全背包的思路,状态属性设置成最小值,背包体积为0时硬币数为1,其他无法实现的情况下需要的硬币数默认设置为amout+1,最后结尾加一个判断,如果最小的硬币数大于amountif(ans<=amount) return ans; else return -1;,就是没有对应的方案。
int f[13][10010];
class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        for (int i = 0; i <= coins.size(); i++)
            for (int j = 1; j <= amount; j++) {
                f[i][j] = amount + 1;
            }
        for (int i = 1; i <= coins.size(); i++)
            for (int j = 0; j <= amount; j++) {
                f[i][j] = f[i - 1][j];   //不选第i号物品
                if (j >= coins[i-1])
                    f[i][j] = min(f[i][j], f[i][j - coins[i-1]] + 1);
            }
        int ans = INT32_MAX;
        for (int i = 1; i <= coins.size(); i++)
            ans = min(ans, f[i][amount]);
        if(ans<=amount) return ans;
        else return -1;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值