一、0/1背包问题
问题描述:有n件物品和容量为m的背包 给出i件物品的重量以及价值 求解让装入背包的物品重量不超过背包容量 且价值最大 。
特点:这是最简单的背包问题,特点是每个物品只有一件供你选择放还是不放。如果想不通代码就填表观察过程。
输入:
5 10 2 6 2 3 6 5 5 4 4 6
输出:
15
① 二维解法
设f[i][j]表示前 i 件物品 总重量不超过 j 的最大价值 可得出状态转移方程
f[i][j]=max{f[i-1][j-a[i]]+b[i], f[i-1][j]}
核心代码
int f[100][100]={0};
for(int i=1;i<=num;i++){ for(int j=capacity;j>=1;j--){ if(weight[i]<=j) {f[i][j]=max(f[i-1][j],f[i-1][j-weight[i]]+value[i]);} else f[i][j]=f[i-1][j]; } }
表格:
②一维解法
设f[j]表示重量不超过j公斤的最大价值 可得出状态转移方程
f[j]=max{f[j], f[j−a[i]]+b[i]}
核心代码
int f[1000]={0};
for(int i=1;i<=num;i++){ for(int j=capacity;j>=weight[i];j--){ f[j]=max( f[j],f[j-weight[i]]+value[i] ); } }
循环的第二层
为什么要从后往前循环!!!!
因为吧,从后往前循环,每次取得状态不会和你之前取得状态重合,这样就符合01背包的要求,每种物品只取一次;不理解填表
表格:
完整代码:
#include <bits/stdc++.h> using namespace std; int main(){ int num,capacity; // 第一行为n值和c值,表示n件物品和背包容量c cin>>num>>capacity; int weight[1000]; int value[1000]; for(int i=1;i<=num;i++){ //每行有两个数据,分别表示第i(1≤i≤n)件物品的重量和价值。 cin>>weight[i]>>value[i]; } int f[1000]={0}; //设f[j]表示重量不超过j公斤的最大价值 可得出状态转移方程f[j]=max{f[j], f[j-a[i]]+b[i]} for(int i=1;i<=num;i++){ for(int j=capacity;j>=weight[i];j--){ f[j]=max( f[j],f[j-weight[i]]+value[i] ); } } cout<<f[capacity]<<endl; return 0; }
二、完全背包问题
问题描述:有n件物品和容量为m的背包 给出i件物品的重量以及价值 求解让装入背包的物品重量不超过背包容量 且价值最大 。
特点:题干看似与01一样 但它的特点是每个物品可以无限选用。
设f[j]表示重量不超过j公斤的最大价值 可得出状态转移方程
f[j] = maxj{f[j], f[j−a[i]]+b[i]}
核心代码
int f[1000]={0}; for(int i=1;i<=num;i++){ for(int j=weight[i];j<=capacity;j++){ f[j]=max( f[j],f[j-weight[i]]+value[i] ); } }
循环的二层
从前往后循环,每次取到的状态都会和前面的状态或多或少都有重叠,这样就刚好的满足了,每种物品无限取得要求了。