背包问题
- 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次.
- 第 i 件物品的体积是 vi,价值是 wi.
- 求总体积不超过背包容量情况下的最大价值
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e3 + 10;
int dp[MAXN] = {0};
int main()
{
int n,v;cin >> n >> v;
for(int i = 1;i <= n;i++)
{
int vi,wi;cin >> vi >> wi;
for(int j = v;j >= vi;j--)
dp[j] = max(dp[j],dp[j - vi] + wi);
}
cout << dp[v];
}
- 从后往前遍历就可以实现一次物品的更新
- 从前往回便是无限次物品的更新
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e3 + 10;
int dp[MAXN] = {0};
int main()
{
int n,v;cin >> n >> v;
for(int i = 1;i <= n;i++)
{
int vi,wi;cin >> vi >> wi;
for(int j = 0;j <= v - vi;j++)
dp[j + vi] = max(dp[j + vi],dp[j] + wi);
}
cout << dp[v];
}
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e2 + 10;
int dp[MAXN] = {0};
int main()
{
int n,v;cin >> n >> v;
for(int i = 1;i <= n;i++)
{
int vi,wi,si;cin >> vi >> wi >> si;
for(int k = 1;k <= si;k++)
for(int j = v;j >= vi;j--)
dp[j] = max(dp[j],dp[j - vi] + wi);
}
cout << dp[v];
}
- 从后往前为一次一次,那么只要来s次从后往前遍历即可(在数据量较小的情况下)
- 同上,当数据量较大时
- 使用二进制优化
- 如10010110b可以分解为01111111b + 00010111b,而如果将二进制的1表示一次计算,那么这个计算的值的范围便是[0~10010110b]
- 从后往前遍历10010110b如果si&1 == 1就执行两次遍历,否者执行一次,然后si>>=1,直到si < 2
#include<bits/stdc++.h>
using namespace std;
const int MAXV = 2e3 + 10;
int dp[MAXV] = {0};
int main()
{
int n,v;cin >> n >> v;
for(int i = 1;i <= n;i++)
{
int vi,wi,si;cin >> vi >> wi >> si;
int ptop = 0;
while(si >= 2)
{
if(si&1)
for(int j = v;j >= vi*(1 << ptop);j--)
dp[j] = max(dp[j],dp[j - vi * (1 << ptop)] + (1 << ptop) * wi);
for(int j = v;j >= vi*(1 << ptop);j--)
dp[j] = max(dp[j],dp[j - vi * (1 << ptop)] + (1 << ptop) * wi);
ptop++;
si >>= 1;
}
for(int j = v;j >= vi;j--)
dp[j] = max(dp[j],dp[j - vi] + wi);
}
cout << dp[v];
}
#include<bits/stdc++.h>
using namespace std;
const int MAXV = 2e4 + 10;
int dp[2][MAXV] = {0};
int deq[MAXV];
int main()
{
ios::sync_with_stdio(false);
int n,v;cin >> n >> v;
int t = 0;
for(int i = 1;i <= n;i++)
{
int vi,wi,si;cin >> vi >> wi >> si;
for(int j = 0;j < vi;j++)
{
int ptop = 0,pend = 0;
deq[0] = 0;
for(int k = 1;v >= k * vi + j;k++)
{
while(pend >= ptop && k - deq[ptop] > si)
ptop++;
int tem = dp[1 - t][k * vi + j];
if(pend >= ptop)
dp[t][k * vi + j] = max(tem,dp[1 - t][deq[ptop] * vi + j] + wi * (k - deq[ptop]));
while(pend >= ptop && tem >= dp[1 - t][deq[pend] * vi + j] + wi * (k - deq[pend]))
pend--;
deq[++pend] = k;
}
}
t = 1 - t;
}
cout << dp[1 - t][v];
}
#include<bits/stdc++.h>
using namespace std;
const int MAXV = 101;
const int MAXM = 101;
int dp[MAXM][MAXV] = {0};
int main()
{
int n,v,m;cin >> n >> v >> m;
for(int i = 1;i <= n;i++)
{
int vi,mi,wi;cin >> vi >> mi >> wi;
for(int j = v;j >= vi;j--)
for(int k = m;k >= mi;k--)
dp[k][j] = max(dp[k][j],dp[k - mi][j - vi] + wi);
}
cout << dp[m][v];
}
- 一组里只能拿一个
- 首先只能拿一个,所以从后往前遍历
- 一组内的物品不相互影响,所以用两个数组代表一组前和一组后的价值
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 101;
int dp[2][MAXN] = {0};
int main()
{
int n,v,t = 1;cin >> n >> v;
while(n--)
{
int si;cin >> si;
for(int i = 1;i <= si;i++)
{
int vi,wi;cin >> vi >> wi;
for(int j = v;j >= vi;j--)
dp[t][j] = max(dp[t][j],dp[1 - t][j - vi] + wi);
}
for(int i = 1;i <= v;i++)
dp[1 - t][i] = dp[t][i];
}
cout << dp[t][v];
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效