01背包方案计数
01背包方案计数
求装到一定容量的方案总数
有\(N\)个物品,每个物品有重量 \(w_i\)和价值\(v_i\)
背包容量为 \(W\)
背包:每个物品要么选 1 次,要么不选。
问法:求恰好\(W\)的情况下,有多少种选物品的方案?
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
const int maxn = 2e5 + 5;
void solve()
{
int n = 0, W = 0;
std::cin >> n >> W;
std::vector<int> w(n + 1, 0), v(n + 1, 0);
std::vector<int> dp(W + 1, 0); dp[0] = 1;
for (int i = 1; i <= n; i++)
{
for (int j = W; j >= w[i]; j--)
{
dp[j] += dp[j - w[i]];
}
}
std::cout << dp[W] << endl;
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr); std::cout.tie(nullptr);
int _t = 1;
// std::cin >> _t;
while (_t--) solve();
return 0;
}
求最优方案总数
令\(f[i][j]\)为在只能放前\(i\)个物品的情况下,容量为\(j\)的背包正好装满所能达到的最大值
每一个\(dp\)状态用一个\(g[i][j]\)来表示方案数
转移方程:
如果
\([f_{i,j} = f_{i-1,j}]\) 且 \([f_{i,j} \neq f_{i-1,j-v}+w]\) 说明我们此时不选择把物品放入背包更优,方案数由
\([g_{i-1,j}]\) 转移过来,
如果
\([f_{i,j} \neq f_{i-1,j}]\) 且 \([f_{i,j} = f_{i-1,j-v}+w]\) 说明我们此时选择把物品放入背包更优,方案数由
\([g_{i-1,j-v}]\) 转移过来,
如果
\([f_{i,j} = f_{i-1,j}]\) 且 \([f_{i,j} = f_{i-1,j-v}+w]\) 说明放入或不放入都能取得最优解,方案数由 \([g_{i-1,j}]\) 和 \([g_{i-1,j-v}]\) 转移过来。
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
const int maxn = 2e5 + 5;
void solve()
{
int n = 0, W = 0;
std::cin >> n >> W;
std::vector<int> w(n + 1, 0), v(n + 1, 0);
std::vector<int> f(W + 1, 0), g(W + 1, 0);
for (int i = 1; i <= n; i++)
{
for (int j = W; j >= w[i]; j--)
{
int tmp = std::max(f[j], f[j - w[i]] + v[i]);
int c = 0;
if (tmp == f[j]) c += g[j];
if (tmp == f[j - w[i] + v[i]]) c += g[i - w[i]];
f[j] = tmp; g[j] = c;
}
}
int mx = 0;
for (int i = 0; i <= W; i++) mx = std::max(mx, f[i]);
int res = 0;
for (int i = 0; i <= W; i++) if (dp[i] == mx) res += cnt[i];
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr); std::cout.tie(nullptr);
int _t = 1;
// std::cin >> _t;
while (_t--) solve();
return 0;
}

浙公网安备 33010602011771号