U1:动态规划是什么
动态规划,简称动规,是针对最优解问题的一种途径,而不是一种算法:
1.它没有一个通用的解法
2.往往是针对一种最优化问题,因而有许多不同的解题方法
动态规划使用要满足什么条件:
最优子结构和无后效性原则
最优子结构:
满足它是可以分解成几个最优子问题
无后效性:这个子问题只会受到之前的答案影响
可以分为几个阶段来完成
U2:动态规划例题
数塔问题
登录 - 沐枫OJhttps://www.mfstem.org/p/524 这道题是一道经典的DP题
没有学 DP 的你,是不是会有贪心的想法呢
这明显不能用贪心
那暴力呢?
O(2^n)会超时,那就是dp了
方程:f[i][j] = a[i][j] + max(f[i+1][j], f[i+1][j+1]);
这是逆推的方法
通过后一行算出的数据,得到这一行的数据
赛马代码环节
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,a[15][15],f[15][15];
signed main(){
int n;
cin >> n;
for(int i = 1;i <= n;++i)
for(int j = 1;j <= i;++j) {
cin >> a[i][j];
f[n][j] = a[i][j];//初始化
}
for(int i = n - 1;i >= 1;--i){
for(int j = 1;j <= i;++j){
f[i][j] = max(f[i + 1][j],f[i + 1][j + 1]) + a[i][j];//状态转移方程
}
}
cout << f[1][1] << endl; //答案
return 0; //qwq
}
U3:背包
背包是DP的一个分支,分为01背包,完全背包,多重背包,分组背包
这次先讲前两个
T1:01背包
顾名思义01背包就是没的东西可以拿一次或不拿
登录 - 沐枫OJhttps://www.mfstem.org/p/565
这是二维的状态转移方程:
f[i][j] = max(f[i - 1][j],f[i - 1][j - w[i]] + c[i]);
f[i][j] 是前i个东西在容量为j的最大值,很容易理解吧,拿和不拿
我们发现,f[i][j]只跟f[i - 1][......]有关,我们可以优化为一维数组
f[j] = max(f[j],f[j - w[i]] + c[i]);
上代码!!!
二维:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int w[40],c[40],f[40][210];
signed main(){
int m,n;
scanf("%lld%lld",&m,&n);
for(int i = 1;i <= n;++i)scanf("%lld%lld",&w[i],&c[i]);
for(int i = 1;i <= n;++i){
for(int j = 0;j <= m;++j){
if(j < w[i])f[i][j] = f[i - 1][j];
else f[i][j] = max(f[i - 1][j],f[i - 1][j - w[i]] + c[i]);
}
}
printf("%lld\n",f[n][m]);
return 0;
}
一维:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int w[40],c[40],f[210];
signed main(){
int m,n;
scanf("%lld%lld",&m,&n);
for(int i = 1;i <= n;++i)scanf("%lld%lld",&w[i],&c[i]);
for(int i = 1;i <= n;++i){
for(int j = m;j >= w[i];--j){
f[j] = max(f[j],f[j - w[i]] + c[i]);
}
}
printf("%lld\n",f[m]);
return 0;
}
T2:完全背包
登录 - 沐枫OJhttps://www.mfstem.org/p/566 完全背包,就是每种物品可以取无数个,问你最大值
方程:
f[i][v] = max(f[i - 1][v],f[i-1][v-k*w[i]]+k*c[i]);
可以改成
f[i][v] = max([i-1][v], f[i][v-w[i]] + c[i]);
#include<bits/stdc++.h>
using namespace std;
int w[37],v[37],f[1005];
int main(void){
int n,m;
cin >> m >> n;
for(int i = 1;i <= n;++i)cin >> w[i] >> v[i];
for(int i = 1;i <= n;++i){
for(int j = w[i];j <= m;++j){
f[j] = max(f[j],f[j - w[i]] + v[i]);
}
}
cout << "max=" << f[m] << endl;
return 0;
}