当前位置: 首页 > news >正文

动态规划篇(背包问题)

目录

一、01背包问题

二、完全背包问题

三、对比01背包和完全背包核心代码

四、多重背包问题Ⅰ

​编辑 五、多重背包问题Ⅱ

​编辑 六、分组背包问题


一、01背包问题

#include<bits/stdc++.h>using namespace std;const int MAXN = 1005;
int v[MAXN];    // 体积
int w[MAXN];    // 价值 
int f[MAXN][MAXN];  // f[i][j], j体积下前i个物品的最大价值 int main() 
{int n, m;   cin >> n >> m;for(int i = 1; i <= n; i++) cin >> v[i] >> w[i];for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++){//  当前背包容量装不进第i个物品,则价值等于前i-1个物品if(j < v[i]) f[i][j] = f[i - 1][j];// 能装,需进行决策是否选择第i个物品else    f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);}           cout << f[n][m] << endl;return 0;
}

代码优化

include<bits/stdc++.h>using namespace std;const int MAXN = 1005;
int f[MAXN];  // int main() 
{int n, m;   cin >> n >> m;for(int i = 1; i <= n; i++) {int v, w;cin >> v >> w;      // 边输入边处理for(int j = m; j >= v; j--)f[j] = max(f[j], f[j - v] + w);}cout << f[m] << endl;return 0;
}

讲解: 

 

二、完全背包问题

动态规划解题步骤
动态规划问题一般从三个步骤进行考虑。

步骤一:集合和集合的状态

所谓的集合,就是一些方案的集合。

用 g[i][j] 表示从前 i 种物品中进行选择,且总体积不大于 j 的各个选法获得的价值的集合。注意:g[i][j] 不是一个数,是一堆数。

例如 g[2][3] 从前 2 种物品中进行选择,且总体积不大于 3 的各个选法获得的价值的集合。

g[2][3] 的可选择方案包括:

方案一:都不选,总价值为 0。
方案二:选 1 件 物品 1,总价值为 2。
方案三:选 2 件物品 1,总价值为 4。
方案四:选 3件 物品 1,总价值为 6。
方案五:选 1 件物品 2,总价值为 4。
方案六:选 1 件物品 2,一件物品 1,总价值为 6。
所以 g[2][3] = {0,2,4,6,4,2}。

i j 取不同的值,对应不同的 g[i][j],也就是对应不同的集合。

用 f[i][j] 表示从前 i 种物品中进行选择,总体积小于等于 j 所能获得的最大价值。很明显,f[i][j] 就是 g[i][j] 中的最大值。i j 取不同的值,就对应不同的 f[i][j]。我们把 f[i][j] 叫做集合的状态。

例如 f[2][3] 表示从前 2 种物品中进行选择,且总体积不大于 3 的获得的最大价值。f[2][3] = max(g[2][3] ) = max( 0,2,4,6,4,2) = 6。

g[i][j] 的最大值就是 f[i][j]。

如果我们能把所有集合对应的最大值都求出来,即求出了 f[0][0] ~ f[N][V], f[N][V] 的含义是在前 N 种物品中进行选择,总体积不大于 V 所获得的最大价值,就是我们要找的答案。

注意,我们不需要把各个集合的所有元素都找出来,只需要求出各个集合的最大值,就能找到答案。下面就是如何求出各个集合的最大值。

步骤二:状态计算

g[i][j] 是从前 i 种物品中进行选择,且总体积不大于 j 的各个选法获得的价值的集合。

f[i][j] 是从前 i 种物品中进行选择,总体积小于等于 j 所能获得的最大价值。

f[i][j] 是集合 g[i][j] 的最大值。

所谓的状态计算是指,如何将把 f[i][j] 算出来。

如果把各个集合 g[i][j] 的状态 f[i][j] 求出来, f[N][V] 就是要找的答案。

回想一下 0 1 背包问题。

01 背包问题把 g[i][j]划分成了 A B 两部分,分别求出这两个部分对应的最大值,然后两者取最大值就是整体 g[i][j] 的最大值,就是 f[i][j]。

01 背包根据是否选择第 i 件物品,也就是第 i 件物品选 0 个还是 1 个,把 g[i][j] 划分成了 A B 两部分,分别求出这两个部分的最大值,然后两者取最大值就是整体 g[i][j] 的最大值,也就求出了 f[i][j]。

完全背包问题也是根据第 i 件物品的选择数量,把 g[i][j] 划分成不同的部分,分别求出各个部分的最大值,取各个部分最大值中的最大值,就是整体 g[i][j] 的最大值,也就求出了 f[i][j]。

因为每种物品的数量是无限的,根据第 i 种物品的选择数量可以把 g[i][j] 分为这样几部分:

A 部分: 第 i 种物品选 0 件。

B 部分:第 i 件物品选 1 件。

C 部分: 第 i 件物品选 2 件。

X 部分: 第 i 件物品选 x 件。

. . . . .

 

#include<iostream>
using namespace std;const int N = 1010;int n, m;
int f[N][N], v[N], w[N];int main(){cin >> n >> m;for(int i = 1; i <= n; i ++ )cin >> v[i] >> w[i];for(int i = 0; i <= m; i++)//初始化{f[0][i] = 0;}for(int i = 1; i <= n; i ++ )for(int j = 0; j <= m; j ++ )for(int k = 0; k * v[i] <= j; k ++ )f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);//求出每一个 f[i][j]cout << f[n][m] << endl;
}

 

for(int i = 1; i <= n; i ++ ){for(int j = 0; j <= m; j ++ ){if(v[i] <= j)//第 i 种能放进去f[i][j] =max(f[i - 1][j], f[i][j - v[i]] + w[i]);else//如果第 i 件物品不能放进去f[i][j] = f[i - 1][j];}}

#include<iostream>
using namespace std;const int N = 1010;int n, m;
int f[N][N], v[N], w[N];int main()
{cin >> n >> m;for(int i = 1; i <= n; i ++ )cin >> v[i] >> w[i];for(int i = 1; i <= n; i ++ ){for(int j = 0; j <= m; j ++ ){if(v[i] <= j)f[i][j] =max(f[i - 1][j], f[i][j - v[i]] + w[i]);elsef[i][j] = f[i - 1][j];}}cout << f[n][m] << endl;
}

三、对比01背包和完全背包核心代码

f[i][j] = max(f[i][j],f[i-1][j-v[i]]+w[i]);//01背包f[i][j] = max(f[i][j],f[i][j-v[i]]+w[i]);//完全背包问题

 

#include<iostream>
using namespace std;
const int N = 1010;
int f[N];
int v[N],w[N];
int main()
{int n,m;cin>>n>>m;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<=m ;j++){f[j] = max(f[j],f[j-v[i]]+w[i]);}cout<<f[m]<<endl;
}

 

四、多重背包问题Ⅰ

 

 

#include <bits/stdc++.h>
using namespace std;
int a[10005],b[10005],t=0,n,m,dp[10005]={ },w,v,s;
int main()
{cin>>n>>m;while(n--){cin>>v>>w>>s;while(s--){a[++t]=v;b[t]=w;}//死拆,把多重背包拆成01背包}for(int i=1;i<=t;i++)for(int j=m;j>=a[i];j--)dp[j]=max(dp[j-a[i]]+b[i],dp[j]);//直接套01背包的板子cout<<dp[m]<<endl;return 0;
}

 优化

#include <bits/stdc++.h>
using namespace std;
int dp[1005],n,t,v,w,s;
main()
{cin>>n>>t;while(n--){cin>>w>>v>>s;while(s--)for(int j=t;j>=w;j--)dp[j]=max(dp[j],dp[j-w]+v);}cout<<dp[t];
}

 五、多重背包问题Ⅱ

 

#include<iostream>
using namespace std;const int N = 12010, M = 2010;int n, m;
int v[N], w[N]; //逐一枚举最大是N*logS
int f[M]; // 体积<Mint main()
{cin >> n >> m;int cnt = 0; //分组的组别for(int i = 1;i <= n;i ++){int a,b,s;cin >> a >> b >> s;int k = 1; // 组别里面的个数while(k<=s){cnt ++ ; //组别先增加v[cnt] = a * k ; //整体体积w[cnt] = b * k; // 整体价值s -= k; // s要减小k *= 2; // 组别里的个数增加}//剩余的一组if(s>0){cnt ++ ;v[cnt] = a*s; w[cnt] = b*s;}}n = cnt ; //枚举次数正式由个数变成组别数//01背包一维优化for(int i = 1;i <= n ;i ++)for(int j = m ;j >= v[i];j --)f[j] = max(f[j],f[j-v[i]] + w[i]);cout << f[m] << endl;return 0;
}

 

 六、分组背包问题

#include<bits/stdc++.h>
using namespace std;const int N=110;
int f[N][N];  //只从前i组物品中选,当前体积小于等于j的最大值
int v[N][N],w[N][N],s[N];   //v为体积,w为价值,s代表第i组物品的个数
int n,m,k;int main(){cin>>n>>m;for(int i=1;i<=n;i++){cin>>s[i];for(int j=0;j<s[i];j++){cin>>v[i][j]>>w[i][j];  //读入}}for(int i=1;i<=n;i++){for(int j=0;j<=m;j++){f[i][j]=f[i-1][j];  //不选for(int k=0;k<s[i];k++){if(j>=v[i][k])     f[i][j]=max(f[i][j],f[i-1][j-v[i][k]]+w[i][k]);  }}}cout<<f[n][m]<<endl;
}

 因为只用到了第i-1列,所以可以仿照01背包的套路逆向枚举体积

#include<bits/stdc++.h>
using namespace std;const int N=110;
int f[N];
int v[N][N],w[N][N],s[N];
int n,m,k;int main(){cin>>n>>m;for(int i=0;i<n;i++){cin>>s[i];for(int j=0;j<s[i];j++){cin>>v[i][j]>>w[i][j];}}for(int i=0;i<n;i++){for(int j=m;j>=0;j--){for(int k=0;k<s[i];k++){    //for(int k=s[i];k>=1;k--)也可以if(j>=v[i][k])     f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);  }}}cout<<f[m]<<endl;
}


文章转载自:

http://2IaGOjUz.Ljpqy.cn
http://MZ8Mem31.Ljpqy.cn
http://S0AwgZvk.Ljpqy.cn
http://QP5z9RuP.Ljpqy.cn
http://YRoe7djw.Ljpqy.cn
http://AQj3EnHB.Ljpqy.cn
http://Cx3X6Mwx.Ljpqy.cn
http://WjfT4wNu.Ljpqy.cn
http://WOttsyBx.Ljpqy.cn
http://B3lRsrzP.Ljpqy.cn
http://NuOEQ94h.Ljpqy.cn
http://5SMD9nqo.Ljpqy.cn
http://6IrrRn0B.Ljpqy.cn
http://0jXfXxFj.Ljpqy.cn
http://r4LbkkWS.Ljpqy.cn
http://x3uCUehI.Ljpqy.cn
http://I5T7fPpP.Ljpqy.cn
http://x796j3dM.Ljpqy.cn
http://9Yx9WyMh.Ljpqy.cn
http://cO4ADOGO.Ljpqy.cn
http://vnNVVqC8.Ljpqy.cn
http://ndAsuTVu.Ljpqy.cn
http://LSdxHDiv.Ljpqy.cn
http://VgyXMkxc.Ljpqy.cn
http://vt3uv65j.Ljpqy.cn
http://WV3s6Sxk.Ljpqy.cn
http://MRzvHbaY.Ljpqy.cn
http://NwZw2ADc.Ljpqy.cn
http://lFlv5dJ5.Ljpqy.cn
http://l8bNW0gM.Ljpqy.cn
http://www.dtcms.com/a/376092.html

相关文章:

  • 线程亲和性(Thread Affinity)
  • 三层交换机实现vlan互通
  • 【项目】在AUTODL上使用langchain实现《红楼梦》知识图谱和RAG混合检索(三)知识图谱和路由部分
  • MyBatis基础到高级实践:全方位指南(上)
  • 开始 ComfyUI 的 AI 绘图之旅-RealESRGAN图生图之图像放大(四)
  • [HUBUCTF 2022 新生赛]help
  • Matlab机器人工具箱6.1 导入stl模型——用SerialLink描述
  • 大数据存储域——Kafka设计原理
  • B站 韩顺平 笔记 (Day 28)
  • Biomedical HPC+AI Platform:48款计算生物学工具集成的一站式高性能在线平台,赋能药物发现
  • Linux 基础 IO 核心知识总结:从系统调用到缓冲区机制(一)
  • 滴滴二面(准备二)
  • leetcode14(判断子序列)
  • 深度学习基本模块:Conv2D 二维卷积层
  • spring中case一直返回else中的值-问题和原理详解
  • 传输层:UDP/TCP协议
  • Java学习之——“IO流“的进阶流之序列化流的学习
  • LeetCode 面试经典 150 题:轮转数组(三次翻转法详解 + 多解法对比)
  • 什么是PFC控制器
  • 【卷积神经网络详解与实例3】——池化与反池化操作
  • Bean的生命周期 高频考点!
  • Redis 主从复制详解:原理、配置与主从切换实战
  • Java锁机制全解析:从AQS到CAS,深入理解synchronized与ReentrantLock
  • 基于SpringBoot的天气预报系统的设计与实现
  • Android 14 servicemanager的前世今生
  • TC_Motion多轴运动-电子齿轮
  • webrtc弱网-DelayBasedBwe 类源码分析与算法原理
  • 【Floor报错注入】
  • Docker生产部署
  • 小型语言模型:智能体AI的未来?