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