代码模板总结:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1000005;
ll dp[maxn];
ll cost[maxn], weight[maxn], amount[maxn];
ll n, v;
void ZeroOnePack(ll cost, ll weight) {
for (ll j = v; j >= cost; --j)//逆序枚举
dp[j] = max(dp[j], dp[j - cost] + weight);//保证第i次循环中的状态f[i][j]是由状态f[i−1][j−w[i]]递推而来
}
void CompletePack(ll cost, ll weight) {
for (ll j = cost; j <= v; ++j)//顺序枚举
dp[j] = max(dp[j], dp[j - cost] + weight);
}
void MultiplePack(ll cost, ll weight, ll amount) {
if (cost * amount >= v) {//此时相当于物品数量无限进行完全背包
CompletePack(cost, weight);
}
else {
for (ll k = 1; k <= amount; k <<= 1) {//二进制拆分
ZeroOnePack(cost * k, weight * k);
amount -= k;//将物品减去
}
ZeroOnePack(amount * cost, amount * weight);
}
}
01背包:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 100005;
const ll MOD = 1e9 + 7;
const ll INF = 0x7fffffff;
ll dp[maxn];
ll cost[maxn], weight[maxn];
ll n, v;
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
cin>>n>>v;
for(int i=1;i<=n;i++)cin>>cost[i]>>weight[i];
for(int i=1;i<=n;i++){
for (ll j = v; j >= cost[i]; j--){//逆序枚举
dp[j] = max(dp[j], dp[j - cost[i]] + weight[i]);//保证第i次循环中的状态f[i][j]是由状态f[i−1][j−w[i]]递推而来
}
}
cout<<dp[v]<<"\n";
return 0;
}
完全背包:
总体积不超过背包容量:题目
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 100005;
const ll MOD = 1e9 + 7;
const ll INF = 0x7fffffff;
ll dp[maxn];
ll cost[maxn], weight[maxn];
ll n, v;
void CompletePack(ll cost, ll weight) {
}
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
cin>>n>>v;
for(int i=1;i<=n;i++)cin>>cost[i]>>weight[i];
for(int i=1;i<=n;i++){
for (ll j = cost[i]; j <= v; j++){//顺序枚举
dp[j] = max(dp[j], dp[j - cost[i]] + weight[i]);
}
}
cout<<dp[v]<<"\n";
return 0;
}
多重背包:
题目一
朴素算法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 100005;
const ll MOD = 1e9 + 7;
const ll INF = 0x7fffffff;
ll dp[maxn];
ll cost[maxn], weight[maxn], amount[maxn];
ll n, v;
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
cin>>n>>v;
for (ll i = 1; i <= n; ++ i)cin >> cost[i] >> weight[i] >> amount[i];
for (ll i = 1; i <= n; ++ i) {
for (ll j = v; j >= cost[i]; -- j)
for (ll k = 0; k <= amount[i] && k * cost[i] <= j; ++ k)
dp[j] = max(dp[j], dp[j - k * cost[i]] + k * weight[i]);
}
cout << dp[v]<<"\n";
return 0;
}
题目二
二进制优化
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1000005;
const ll MOD = 1e9 + 7;
const ll INF = 0x7fffffff;
ll dp[maxn];
ll cost[maxn], weight[maxn], amount[maxn];
ll n, v;
void ZeroOnePack(ll cost, ll weight) {
for (ll j = v; j >= cost; --j)//逆序枚举
dp[j] = max(dp[j], dp[j - cost] + weight);//保证第i次循环中的状态f[i][j]是由状态f[i−1][j−w[i]]递推而来
}
void CompletePack(ll cost, ll weight) {
for (ll j = cost; j <= v; ++j)//顺序枚举
dp[j] = max(dp[j], dp[j - cost] + weight);
}
void MultiplePack(ll cost, ll weight, ll amount) {
if (cost * amount >= v) {//此时相当于物品数量无限进行完全背包
CompletePack(cost, weight);
}
else {
for (ll k = 1; k <= amount; k <<= 1) {//二进制拆分
ZeroOnePack(cost * k, weight * k);
amount -= k;//将物品减去
}
ZeroOnePack(amount * cost, amount * weight);
}
}
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
cin>>n>>v;
for (int i = 1; i <= n; ++i)cin >> cost[i]>>weight[i]>>amount[i];
for (int i = 1; i <= n; ++i)MultiplePack(cost[i], weight[i], amount[i]);
cout << dp[v]<<"\n";
return 0;
}
题目三
单调队列优化
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 100005;
const ll MOD = 1e9 + 7;
const ll INF = 0x7fffffff;
ll dp[maxn];
ll cost[maxn], weight[maxn], amount[maxn];
ll ans[maxn];
ll n, v;
struct node {
ll pos, val;
}q[maxn];
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
cin >> n >> v;
for (ll i = 1; i <= n; i++)cin >> cost[i] >> weight[i] >> amount[i];
for (ll i = 1; i <= n; i++){
for (ll j = 0; j < cost[i]; j++) {
ll hh = 0, tt = 0, stop = (v - j) / cost[i];
for (ll k = 0; k <= stop; ++k) {
ll val = dp[k * cost[i] + j] - k * weight[i];
while (hh < tt && val >= q[tt - 1].val) --tt;
q[tt].pos = k, q[tt++].val = val;
if (q[hh].pos < k - amount[i]) ++hh;
dp[cost[i] * k + j] = q[hh].val + k * weight[i];
}
}
}
cout<<dp[v];
return 0;
}
二维费用背包:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1005;
const ll MOD = 1e9 + 7;
const ll INF = 0x7fffffff;
ll dp[maxn][maxn];
ll cost1[maxn], weight[maxn], cost2[maxn];
ll n, v, m;
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
cin >> n >> v >> m;
for (int i = 1; i <= n; i++)cin >> cost1[i] >> cost2[i] >> weight[i];
for (int i = 1; i <= n; i++) {
for (int j = v; j >= cost1[i]; j--) {
for (int k = m; k >= cost2[i]; k--) {
dp[j][k] = max(dp[j][k], dp[j - cost1[i]][k - cost2[i]] + weight[i]);
}
}
}
cout << dp[v][m];
return 0;
}
分组背包:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1005;
const ll MOD = 1e9 + 7;
const ll INF = 0x7fffffff;
ll dp[maxn];
ll cost[maxn][maxn], weight[maxn][maxn];
ll n, v;
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
cin >> n >> v;
ll num[maxn];
for (ll i = 1; i <= n; i++) {
cin >> num[i];
for (ll j = 1; j <= num[i]; j++) {
cin >> cost[i][j] >> weight[i][j];
}
}
for(ll i=1;i<=n;i++)
for(ll j=v;j>=0;j--)
for(ll k=1;k<=num[i];k++)
if(j>=cost[i][k])dp[j]=max(dp[j],dp[j-cost[i][k]]+weight[i][k]);
cout << dp[v];
return 0;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1005;
const ll MOD = 1e9 + 7;
const ll INF = 0x7fffffff;
ll dp[maxn];
ll cost[maxn][maxn], weight[maxn][maxn];
ll n, v;
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
cin >> v >> n;
vector<ll> gruop[maxn];
set<ll> gruop_num;
for (ll i = 1; i <= n; i++) {
ll c, w, g;
cin >> c >> w>> g;
gruop[g].push_back(g);
gruop_num.insert(g);
cost[g][gruop[g].size()] = c;
weight[g][gruop[g].size()] = w;
}
for (ll i = 1; i <= gruop_num.size(); i++)
for (ll j = v; j >= 0; j--)
for (ll k = 1; k <= gruop[i].size(); k++)
if (j >= cost[i][k])dp[j] = max(dp[j], dp[j - cost[i][k]] + weight[i][k]);
cout << dp[v];
return 0;
}
背包问题求总方案数:
0/1背包求方案数:总体积不超过背包容量:题目
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1005;
const ll MOD = 1e9 + 7;
const ll INF = 0x7fffffff;
ll dp[maxn];
ll cost[maxn], weight[maxn];
ll ans[maxn];
ll n, v;
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
cin >> n >> v;
for (ll i = 1; i <= n; i++) cin >> cost[i] >> weight[i];
for (ll i = 0; i <= v; i++)ans[i] = 1;
for (int i = 1; i <= n; i++) {
for (ll j = v; j >= cost[i]; j--) {
ll left = dp[j], right = dp[j - cost[i]] + weight[i];
dp[j] = max(left, right);
if (left > right)ans[j] = ans[j];
else if (left < right)ans[j] = ans[j - cost[i]];
else ans[j] = ans[j] + ans[j - cost[i]];
ans[j] %= MOD;
}
}
cout<<ans[v];
return 0;
}
0/1背包求方案数:总体积恰好为背包容量题目
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1005;
const ll MOD = 1e9 + 7;
const ll INF = 0x7fffffff;
ll dp[maxn];
ll cost[maxn];
ll ans[maxn];
ll n, v;
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
cin >> n >> v;
for (ll i = 1; i <= n; i++) cin >> cost[i];//每个物体的花费
dp[0]=1;//初始为1
for (int i = 1; i <= n; i++) {//遍历每个物品
for (ll j = v; j >= cost[i]; j--) {
dp[j] += dp[j - cost[i]];
}
}
cout << dp[v];
return 0;
}
完全背包求方案数:总体积恰好为背包容量题目
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 4005;
const ll MOD = 2147483648;
const ll INF = 0x7fffffff;
ll dp[N];
ll n;
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
cin >> n ;
dp[0]=1;//初始为1
for (ll i = 1; i < n; i++) {
for (ll j = i; j <= n; j++) {
dp[j] = (dp[j]+dp[j - i])%MOD;//保证从最开始转移到最后
}
}
cout << dp[n] << "\n";
return 0;
}
背包问题求具体方案:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1005;
const ll MOD = 1e9 + 7;
const ll INF = 0x7fffffff;
ll dp[maxn][maxn];
ll cost[maxn], weight[maxn];
ll n, v;
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
cin >> n >> v;
for (ll i = 1; i <= n; i++) cin >> cost[i] >> weight[i];
for (ll i = n; i >= 1; i--) {
for (ll j = 0; j <= v; j++) {
dp[i][j] = dp[i + 1][j];
if (cost[i] <= j) dp[i][j] = max(dp[i][j], dp[i + 1][j - cost[i]] + weight[i]);
}
}
ll temp = v;
for (ll i = 1; i <= n; i++) {//如果是最后一个元素,特判一下,防止越界即可
if (i == n && temp >= cost[i]) {
cout << i << " ";
break;
}
if (temp <= 0)break;
//判断下标是否越界
if (temp - cost[i] >= 0 && dp[i][temp] == dp[i + 1][temp - cost[i]] + weight[i]) {
cout << i << " ";
temp = temp - cost[i];//选了第i个物品,剩余容量就要减小。
}
}
return 0;
}