
背包问题(动态规划)模板
发布日期:2021-05-07 03:05:44
浏览次数:29
分类:精选文章
本文共 3951 字,大约阅读时间需要 13 分钟。
文章目录
1. 01背包
有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。数据范围
0<N,V≤1000 0<vi,wi≤1000 输入样例 4 5 1 2 2 4 3 4 4 5 输出样例: 8(1)状态f[i][j]定义:前 i个物品,背包容量 j下的最优解(最大价值):
当前的状态依赖于之前的状态,可以理解为从初始状态f[0][0] = 0开始决策,有 N件物品,则需要 N 次决 策,每一次对第 i件物品的决策,状态f[i][j]不断由之前的状态更新而来。
(2)当前背包容量不够(j < v[i]),没得选,因此前 i 个物品最优解即为前 i−1 个物品最优解:
对应代码:f[i][j] = f[i - 1][j]。
(3)当前背包容量够,可以选,因此需要决策选与不选第 i 个物品:
选:f[i][j] = f[i - 1][j - v[i]] + w[i]。
不选:f[i][j] = f[i - 1][j]
二维形式:
每次取最大值
#includeusing namespace std;int V,N;int v[1005],w[1005];int f[1005][1005];int main(){ cin>>N>>V; for(int i=1;i<=N;i++) cin>>v[i]>>w[i]; for(int i=1;i<=N;i++) { for(int j=0;j<=V;j++) { f[i][j]=f[i-1][j];// if(j>=v[i]) f[i][j] = max(f[i][j],f[i][j-v[i]]+w[i]); } } cout< <<"\n"; return 0; }
一维形式:
#includeusing namespace std;const int maxn = 1e3+5;int f[maxn];int v[maxn],w[maxn];int N,V;int main(){ cin>>N>>V; for(int i=1;i<=N;i++) cin>>v[i]>>w[i]; //想象方格 for(int i=1;i<=N;i++) for(int j=V;j>=v[i];j--) f[j] = max(f[j],f[j-v[i]]+w[i]); cout< <<"\n"; return 0;}
注意:体积要从v到v[i],只能降序。
2. 完全背包
二维形式:
#includeusing namespace std;int V,N;int v[1005],w[1005];int f[1005][1005];int main(){ //二维 cin>>N>>V; for(int i=1;i<=N;i++) cin>>v[i]>>w[i]; for(int i=1;i<=N;i++) { for(int j=0;j<=V;j++) { f[i][j]=f[i-1][j]; if(j>=v[i]) f[i][j] = max(f[i][j],f[i][j-v[i]]+w[i]); } } cout< <<"\n"; return 0; }
一维形式:
#includeusing namespace std;int N,V;int f[maxn];int main(){ cin>>N>>V; for(int i=1;i<=N;i++) cin>>v[i]>>w[i]; for(int i=1;i<=N;i++) { for(int j=v[i];j<=V;j++) { f[j] = max(f[j],f[j-v[i]]+w[i]); } } cout< <<"\n"; return 0; }
注意:体积从v[i]到v。
3. 多重背包
一二维形式:
#includeusing namespace std;typedef long long ll;const int maxn = 1e3;const int INF = 0x3f3f3f3f;int f[maxn];int v[maxn],w[maxn],num[maxn];int N,V;int main(){ //多重循环 cin>>N>>V; for(int i=1;i<=N;i++) cin>>v[i]>>w[i]>>num[i]; for(int i=1;i<=N;i++) { for(int j=V;j>=0;j--) { for(int k=1;k<=num[i];k++) { if(j-k*v[i]>=0) f[j] = max(f[j],f[j-k*v[i]]+k*w[i]);// f[i][j] = max(f[i-1][j],f[i-1][j-k*v[i]]+k*w[i]); } } } cout< <<"\n"; return 0;}
二进制压缩:
//二进制压缩 #includeusing namespace std;typedef long long ll;const int maxn = 1e3+5;int f[15005],s[maxn],w[maxn],v[maxn];int nw[15005],nv[15005];int V,N;int main(){ cin>>N>>V; for(int i=1;i<=N;i++) cin>>v[i]>>w[i]>>s[i]; int total = 1; for(int i=1;i<=N;i++) { for(int j=1;j<=s[i];j<<=1) { nv[total] = j*v[i]; nw[total++] = j*w[i]; s[i]-=j; } if(s[i]) { nv[total] = s[i]*v[i]; nw[total++] = s[i]*w[i]; } } //01背包 for(int i=1;i =nv[i];j--) { f[j] = max(f[j],f[j-nv[i]]+nw[i]); } } cout< <<"\n"; return 0;}
单调队列优化:
//单调队列优化#includeusing namespace std;int n,m;int f[20002],q[20002],g[20002];int main(){ cin>>n>>m; for(int i=1;i<=n;i++) { int v,w,s; cin>>v>>w>>s; memcpy(g,f,sizeof(f)); //滚动数组优化空间,g[]即f[i-1][]; for(int j=0;j q[hh]) //如果当前窗口的内容超过了s个; { hh++; } if(hh<=tt) { f[k]=max(f[k],g[q[hh]]+(k-q[hh])/v*w); //max(f[i-1][k],f[i-1][能转移里最大]+数*v[i]); } while(hh<=tt && g[q[tt]]-(q[tt]-j)/v*w <= g[k]-(k-j)/v*w) { tt--; } q[++tt]=k; } } } cout< <
发表评论
最新留言
路过按个爪印,很不错,赞一个!
[***.219.124.196]2025年04月09日 18时42分47秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
.net Core 使用IHttpClientFactory请求
2021-05-09
多线程之旅(准备阶段)
2021-05-09
Python 之网络式编程
2021-05-09
MySql5.5安装步骤及MySql_Front视图配置
2021-05-09
springmvc Controller详解
2021-05-09
mybatis #{}和${}区别
2021-05-09
Java Objects工具类重点方法使用
2021-05-09
Java内存模型(JMM)
2021-05-09
AQS相关
2021-05-09
abp(net core)+easyui+efcore实现仓储管理系统——多语言(十)
2021-05-09
WCF学习之旅—第三个示例之一(二十七)
2021-05-09
java ThreadPoolExecutor初探
2021-05-09
Markdown进阶
2021-05-09
快速指数算法
2021-05-09
python去除字符串中的特殊字符(爬虫存储数据时会遇到不能作为文件名的字符串)
2021-05-09
PHP将网址快捷方式保存到桌面
2021-05-09