什么是 DP ?
DP阵营图 | 必须要有状态转移 | 其实有转移就可以 | 一定要有转移吗? |
---|---|---|---|
一定要求的最优化 | 动态规划毫无疑问是DP | 搜索也可以是DP | 静态规划为什么不是DP? |
不用最优也可以 | 神经网络是DP | 二分也是DP | 蒙特卡洛当然也是DP |
最优是什么? | 递归难道不是DP? | 映射也很DP | Dual Problem才是正统DP! |
咳咳,这里的DP可不是Dual Problem,而是Dynamic Programming。
按解法分类,可以将动态规划以下几类:
- 暴力
- 暴力+优化
- 暴力+算法
- 暴力+算法+优化
- 挖坑待填
- 挖坑待填
咳咳,简单来说就是,简单的选与不选,和困难的选与不选。当然,分类不重要,毕竟它是我主观的,在成体系前你看不懂就没用。所以,前四类就统称为暴力好了。
当然,我认为背包问题不能算进分类里。它是板子,人人都应该会和背。
背包问题
什么是背包问题
有物品,有背包,有题目就是背包问题
咳咳。题目会给出一个或多个限制,和一些供选取的东西,问怎么选东西最优之类的。
果然还是不懂吧,说了白说,直接看题。
01背包
体积V。N种物品,各体积vi,价值wi,每种最多选1个。问最大价值。
#include<bits/stdc++.h>//acwing2
using namespace std;
int N,V,v[1010],w[1010],dp[1010];
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--) {
dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
}
}
cout<<dp[V];
return 0;
}
显然可分为装与不装,那么dp[i]表示体积为i时的最大价值。
那么暴力枚举每件物品i,对于能装下v[i]所有体积,在装与不装之间取最优:
for i:1->N
for j:v->V
dp[i]=max(self,dp[i-v]+w)
但是考虑后无效性,枚举体积时倒序:
for i:1->N
for j:V->v
dp[i]=max(self,dp[i-v]+w)
完全背包
体积V。N种物品,体积vi,价值wi,可无限选。问最大价值。
#include<bits/stdc++.h>//acwing3
using namespace std;
int N,V,v[1010],w[1010],dp[1010];
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++) {
//
dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
}
}
cout<<dp[V];
return 0;
}
显然,代码上相对01背包就变了个循环方向。
01背包需要确保后无效性,而完全背包需要确保后有效性。
分组背包
体积V。N组物品,物品体积vij价值wij。限制每组的选择策略。问最大价值。
它规定了组内的某种选择规则,所以叫分组背包。
例1
总体积V,N组物品,每组最多选1个,物品体积vij价值wij。问最大价值。
#include<bits/stdc++.h>//acwing9
using namespace std;
int N,V,n[110],v[110][110],w[110][110];
int f[110][10010];
int main() {
cin>>N>>V;
for