01背包
有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。第 i 件物品的体积是 vi,价值是 wi,求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
思路
每个物品只有一件,考虑拿与不拿,在前i件物品中,拿第i件物品与不拿第i件物品,其限制条件是背包的空间,那么状态可表示为dp[前i件物品][背包容量],当前状态依赖于之前的状态,考虑前i件物品拿与不拿,状态转移方程可表示为,dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]),不拿第i件物品,那么就是在当前体积为j的情况下去拿,拿了第i件物品,那么就从前i-1件物品中,在j-v[i]的体积去拿。这样可以枚举出所有情况。
朴素写法
#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization ("unroll-loops")
using namespace std;
#define ll long long
#define sl(n) scanf("%lld",&n)
#define pl(n) printf("%lld",n)
#define sdf(n) scanf("%lf",&n)
#define pdf(n) printf("%.lf",n)
#define pE printf("\n")
#define ull unsigned long long
#define pb push_back
#define pre(n) for(ll i=1;i<=n;i++)
#define rep(n) for(ll i=n;i>=1;i--)
#define ph push
#define pi pair<ll,ll>
#define fi first
#define se second
ll n, v, volume[1010], value[1010];
ll dp[1010][1010];
int main()
{
cin >> n >> v;
pre(n)cin >> volume[i] >> value[i];
for (ll i = 1; i <= n; i++)
{
for (ll j = 1; j <= v; j++)
{
dp[i][j] = dp[i - 1][j];
if (j >= volume[i])dp[i][j] = max(dp[i][j], dp[i - 1][j - volume[i] ]+ value[i]);
}
}
cout << dp[n][v];
return 0;
}
优化空间
dp[i][j] = dp[i - 1][j];
if (j >= volume[i])dp[i][j] = max(dp[i][j], dp[i - 1][j - volume[i] ]+ value[i]);
这里的i在内层循环中一直没有发生过变化,那么可以优化到一维dp,二维dp是dp[i][j]表示前i件物品的最大价值,那么优化到一维状态只表示背包的容量,那么对原式做等价变形,if (j >= volume[i])只有当前背包体积大于等于当前物品体积时,才能放进去并进行比较,状态才会发生变化,那么你从大到小进行遍历
for (ll i = 1; i <= n; i++)
{
for (ll j = v; j >= volume[i] ; j--)dp[j] = max(dp[j], dp[j - volume[i]] + value[i]);
}
为什么大到小遍历是正确的呢,因为当你更新dp[j]时,它的每一次状态都是从i-1的状态,和原式是等价的
#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization ("unroll-loops")
using namespace std;
#define ll long long
#define sl(n) scanf("%lld",&n)
#define pl(n) printf("%lld",n)
#define sdf(n) scanf("%lf",&n)
#define pdf(n) printf("%.lf",n)
#define pE printf("\n")
#define ull unsigned long long
#define pb push_back
#define pre(n) for(ll i=1;i<=n;i++)
#define rep(n) for(ll i=n;i>=1;i--)
#define ph push
#define pi pair<ll,ll>
#define fi first
#define se second
ll n, v, volume[1010], value[1010];
ll dp[1010];
int main()
{
cin >> n >> v;
pre(n)cin >> volume[i] >> value[i];
for (ll i = 1; i <= n; i++)
{
for (ll j = v; j >= volume[i] ; j--)dp[j] = max(dp[j], dp[j - volume[i]] + value[i]);
}
cout << dp[v];
return 0;
}