背包的状态转换方程
i:表示物品序号
j:表示背包大小
W [i]:表示第i件物品的重量
f[i,j]:表示在前i件物品中选择若干件放在承重为 j 的背包中,可以取得的最大价值
f[i-1,j-Wi]:表示在前i-1件物品中选择若干件放在承重为j-Wi的背包中,可以取得的最大价值
Pi(j>=Wi):表示第i件物品的价值,要求背包大小j要大于此件物品的重量
f[i-1,j]:表示前i-1件物品中选择若干件放在承重为j的背包中,可以取得的最大价值
1.01背包问题2. 01背包问题 - AcWing题库
首先我们创立两个一维数组,用来存储大小和价值
再创立一个二维数组用来状态分析
分析背包问题我们是曲线救国,调用已经存在的数据元素来解决问题
物品个数是从1到n,然后分别得出该个数下的最大价值
我们要分析两个状态,放与不放,
第一种--不放i物品:f[i][j]=f[i-1][j](调用的是i-1状态下的最大值)
第二种--放i物品:f[i][j]=f[i-1] [j-v[i]] + w[i](此时同时是调用i-1个物品下的状态,
但是此时放物品那你要留空给这个物品放,so,此时调用的状态转移方程容量是j-v[i]条件下的,
最后再加上w[i]就是该状态下的value了)(当然,背包的容量要大于v[i]要不然放不下i 物品)
last but not least,我们要对两种状态,放与不放的价值大小进行判断
f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i])
最后输出则可。
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int main(){
int n,m;
int v[N],w[N];
int f[N][N];
cin>>n>>m;
for (int i=1;i<=n;i++) cin>>v[i]>>w[i];
for (int i=1;i<=n;i++)//物品个数 1-n
for (int j=0;j<=m;j++){//容量 0-m
f[i][j]=f[i-1][j];//先赋值给不放第i个,在下面再比较放与不妨
if (j>=v[i]) f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);//f[i][j]= (1) f[i-1][j] (2) f[i-1][j-v[i]]+w[i]
//第一种情况是取的是i-1个物品的最大 容量为j
//第二种是[i-1]个但是把第i个放入的情况,那要取的是【i-1】,但是其内存要是j-v[i]--相当于留了一个地方存这个物品,取得是之前的最后再加上w[i]成为新的f[i][j]
}
cout<<f[n][m]<<endl;
return 0;
}
n,m=map(int,input().split())#n是物品,m是容量
v=[]#容量
w=[]#价值
v.append(0)
w.append(0)
f=[[0 for j in range(n+m)] for i in range(m+n)]
for i in range(n):
a,b=map(int,input().split())
v.append(a)
w.append(b)
for i in range(1,n+1):
for j in range(0,m+1):
f[i][j]=f[i-1][j]
if j>=v[i]:
f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i])
print(f[n][m])
2.完全背包问题3. 完全背包问题 - AcWing题库
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int v[N],w[N];
int f[N][N];
int n,m;
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++)
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]);
cout<<f[n][m]<<endl;
return 0;
}
n, m = map(int, input().split())
v, w = [0] * (n + 1), [0] * (n + 1)
for i in range(1, n + 1):
v[i], w[i] = map(int, input().split())
# 二维:
# 状态表示f[i][j] 选择前i个物品,总体积小于等于j的最大价值
# 状态计算f[i][j] = max(f[i-1][j], f[i][j - v[i] + w[i] if j >= v[i])
# 物品种类不限,所以max中第二项和0-1背包不同
f = [[0] * (m + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
for j in range(m + 1):
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])
print(max(f[n]))
n, m = map(int, input().split())
v, w = [0] * (n + 1), [0] * (n + 1)
for i in range(1, n + 1):
v[i], w[i] = map(int, input().split())
# 一维:f[j] 代表总体积小于等于j的最大价值
# 因为每种物品数量不限,所以j从小到大更新,即可以使用前面当前层j更新后的结果
f = [0] * (m + 1)
for i in range(1, n + 1):
for j in range(v[i], m + 1):
f[j] = max(f[j], f[j-v[i]] + w[i])
print(f[m])
3.多重背包问题4. 多重背包问题 I - AcWing题库
#include <bits/stdc++.h>
using namespace std;
const int N=110;
int v[N],w[N],s[N];
int f[N][N];
int main()
{
int n,m;
cin>>n>>m;
for (int i=1;i<=n;i++) cin>>v[i]>>w[i]>>s[i];
for (int i=1;i<=n;i++)
for (int j=0;j<=m;j++){
for(int k=0;k<=s[i] && k*v[i]<=j;k++)
{
f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+w[i]*k);
}
}
cout<<f[n][m]<<endl;
return 0;
}
n,v = map(int, input().split())
goods = []
for i in range(n):
goods.append([int(i) for i in input().split()])
new_goods = []
for i in range(n):
for j in range(goods[i][2]):
new_goods.append(goods[i][0:2])
goods = new_goods
n = len(goods)
dp = [0 for i in range(v+1)]
for i in range(n):
for j in range(v,-1,-1):
if j>= goods[i][0]:
dp[j] = max(dp[j], dp[j - goods[i][0]] + goods[i][1])
print(dp[-1])
4.数字三角形3304. 数字三角形 - AcWing题库
数字三角形属于线性DP问题。状态表示也是一个2维数组,f[i][j],i,j分别表示行与列
状态分析同时也是f[i][j]调用已经存在的状态值,该题的f[i][j]可以由两个方向过来,左上右上,
左上:f[i-1][j-1]+a[i][j]
右上:f[i-1][j]+a[i][j]
f [i][j]=max ( f [i-1] [j-1] + a[i] [j] , f [i-1] [j] + a[i] [j])
数字三角形题目还需注意左右次数的问题。
#include<iostream>
using namespace std;
const int N = 510 , M = -1e9;;
int n;
int a[N][N];
int f[N][N];
int main(){
cin >> n;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= i; j++){
cin >> a[i][j];
}
}
for(int i = 0; i <= n; i++){
for(int j = 0; j <= i+1; j++){
//注意这里的循环判断条件 从零开始到最后一个数字的后一个位置都要初始化,因为他会用到左边界和右边界上的值.
f[i][j] = M;
}
}
f[1][1] = a[1][1];
for(int i = 2; i <= n; i++){
//前面第一个位置只有一种情况,所以从2开始
for(int j = 1; j <= i; j++){
f[i][j] = max(f[i-1][j-1]+a[i][j], f[i-1][j]+a[i][j]);
}
}
if (n % 2 == 0) cout << max(f[n][n / 2], f[n][n / 2 + 1]) << '\n';
else cout << f[n][n / 2 + 1];
return 0;
}
n=int(input())
arrs=[[0 for i in range(1,n+1+1)] for i in range(n+1)]#存数的数组
arr=[[0 for i in range(1,n+3)] for i in range(n+1)]#动态规划状态调用数组
for i in range(1,n+1):
arrs[i][1:n]=list(map(int,input().split()))
arr[1][1] =arrs[1][1]
for i in range(2,n+1):
for j in range(1,i+1):
arr[i][j]=max(arr[i-1][j-1]+arrs[i][j],arr[i-1][j]+arrs[i][j])
if n % 2 == 1:
print(arr[-1][n//2 + 1])
else:
print(max(arr[-1][n//2],arr[-1][n//2+1]))
注:作者一些题目的解法可能并不是最优解,可以就行指出探讨。