1、0-1背包问题
空间优化方案
#include <bits/stdc++.h>
using namespace std;
int main()
{
int N, V;
cin >> N >> V;
vector<int> v(N);
vector<int> w(N);
for(int i = 0; i < N; i++)
{
cin >> v[i] >> w[i];
}
vector<int> dp(V + 1);
for(int i = 0; i < N; i++)
{
for(int j = V; j >= v[i]; j--)
{
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
}
cout << dp[V] <<endl;
return 0;
}
2、完全背包问题
每个物体可以无限次使用
对于体积,从前往后走 保证物体可以取多次
#include <bits/stdc++.h>
using namespace std;
int main()
{
int N, V;
cin >> N >> V;
vector<int> v(N);
vector<int> w(N);
for(int i = 0; i < N; i++)
{
cin >> v[i] >> w[i];
}
vector<int> dp(V + 1);
for(int i = 0; i < N; i++)
{
for(int j = v[i]; j <= V; j++)
{
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
}
cout << dp[V] <<endl;
return 0;
}
3、多重背包问题
#include <bits/stdc++.h>
using namespace std;
int main()
{
int N, V;
cin >> N >> V;
vector<int> v(N);
vector<int> w(N);
vector<int> s(N);
for(int i = 0; i < N; i++)
{
cin >> v[i] >> w[i] >> s[i];
}
vector<int> dp(V + 1);
for(int i = 0; i < N; i++)
{
for(int j = V; j >= v[i]; j--)
{
for(int k = 1; k <= s[i] && k * v[i] <= j; k++)
{
dp[j] = max(dp[j], dp[j - k * v[i]] + k * w[i]);
}
}
}
cout << dp[V] << endl;
return 0;
}
4、多重背包问题优化
1、二进制优化
#include <bits/stdc++.h>
using namespace std;
struct Good
{
int v;
int w;
};
int main()
{
int N, V;
cin >> N >> V;
vector<Good> res;
int v, w, s;
for(int i = 0; i < N; i++)
{
cin >> v >> w >> s;
for(int k = 1; k <= s; k *= 2) //将s个物品拆分,转换为0-1背包问题
{
s -= k;
res.push_back({k * v, k * w});
}
if(s > 0)
res.push_back({s * v, s * w});
}
vector<int> dp(V + 1);
for(auto good : res)
{
for(int j = V; j >= good.v; j--)
{
dp[j] = max(dp[j], dp[j - good.v] + good.w);
}
}
cout << dp[V] << endl;
return 0;
}
2、单调队列优化
略
5、混合背包问题
#include <bits/stdc++.h>
using namespace std;
struct Good
{
int kind;
int v, w;
};
vector<Good> good;
int main()
{
int N, V;
cin >> N >> V;
for(int i = 0; i < N; i++)
{
int v, w, s;
cin >> v >> w >> s;
if(s < 0)
good.push_back({-1, v, w}); //0-1背包问题
else if(s == 0)
good.push_back({0, v, w}); //完全背包问题 从小到大遍历
else
//将多重背包问题化解为0-1背包问题
{
for(int k = 1; k <= s; k *= 2)
{
s -= k;
good.push_back({-1, k * v, k * w});
}
if(s > 0)
good.push_back({-1, s * v, s * w});
}
}
vector<int> dp(V + 1);
for(auto goo : good)
{
if(goo.kind == -1)
{
for(int j = V; j >= goo.v; j--)
{
dp[j] = max(dp[j], dp[j - goo.v] + goo.w);
}
}
else
{
for(int j = goo.v; j <= V; j++)
{
dp[j] = max(dp[j], dp[j - goo.v] + goo.w);
}
}
}
cout << dp[V] <<endl;
return 0;
}
6、二维费用背包问题
#include <bits/stdc++.h>
using namespace std;
int main()
{
int N, V, M;
cin >> N >> V >> M;
vector<vector<int>> dp(V + 1, vector<int>(M + 1));
for(int i = 0; i < N; i++)
{
int v, m, w;
cin >> v >> m >> w;
for(int j = V; j >= v; j--)
{
for(int k = M; k >= m; k--)
{
dp[j][k] = max(dp[j][k], dp[j - v][k - m] + w);
}
}
}
cout << dp[V][M] <<endl;
return 0;
}
7、分组背包问题
#include <bits/stdc++.h>
using namespace std;
int main()
{
int N, V;
cin >> N >> V;
vector<int> v(N);
vector<int> w(N);
vector<int> dp(V + 1);
for(int i = 0; i < N; i++)
{
int s;
cin >> s;
for(int j = 0; j < s; j++)
{
cin >> v[j] >> w[j];
}
for(int j = V; j >= 0; j--)
{
for(int k = 0; k < s; k++)//对于每组的物品,不选或者从1选到s
{
if(j >= v[k])
{
dp[j] = max(dp[j], dp[j - v[k]] + w[k]);
}
}
}
}
cout << dp[V] << endl;
return 0;
}
8、背包问题方案数
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int main()
{
int N, V;
cin >> N >> V;
vector<int> dp(V + 1);
vector<int> cnt(V + 1); //记录最优方案数
for(int i = 0; i < V; i++)
cnt[i] = 1; //初始化为1,即不选也是种方案
for(int i = 0; i < N; i++)
{
int v, w;
cin >> v >> w;
for(int j = V; j >= v; j--)
{
int value = dp[j - v] + w;
if(value > dp[j])
{
dp[j] = value;
cnt[j] = cnt[j - v];
}
else if(value == dp[j])
cnt[j] = (cnt[j] + cnt[j - v]) % mod; //两种方案相加
}
}
cout << cnt[V] <<endl;
return 0;
}