动态规划
一、动态规划的基本思想
求解问题分为多个阶段或多个子问题,然后按顺序求解各个问题,最后一个子问题就是初始问题的解。
动态规划=贪婪策略+递推+存储递推结果
空间换取时间
基本要素:
最优化子结构性质和重叠子问题性质
二、主要概念
阶段:把问题分为几个相互联系的有顺序的几个环节,这些称为阶段。
状态:某一阶段发出的位置称为状态。
决策:从某一阶段的一个状态演变到下一个阶段的某一个状态的选择。
状态转移方程
三、适合解决的问题
最优化原理:最优子结构
无后向性:某状态一旦确定后,就不受这个状态以后决策的影响。
四、步骤
(1)划分阶段(2)选择状态(3)确定决策并写出状态转移方程
五、PPT例题
1.数塔问题
一个数塔,可以选择向左或者向右走,要求走出一条路径,数值和最大。
状态转移方程:
//状态转移方程
if(a[i+1][j]>a[i+1][j+1]){
a[i][j]=a[i][j]+a[i+1][j];
}
else{
a[i][j]=a[i][j]+a[i+1][j+1];
}
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
int a[100][100];
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
cin>>a[i][j];
}
}
//自下而上
for(int i=n-1;i>=1;i--){
for(int j=1;j<=i;j++){
//状态转移方程
if(a[i+1][j]>a[i+1][j+1]){
a[i][j]=a[i][j]+a[i+1][j];
}
else{
a[i][j]=a[i][j]+a[i+1][j+1];
}
}
}
cout<<a[1][1];
}
2.n个矩阵连乘问题
不会
3.求两个字符串的最长公共字符子序列
详情见这里
4.求一个数列最长不降子序列
详情见这里
5.0-1背包问题
给定的n种物品和一个背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,是的其物品价值最大。
状态方程:
//状态转移方程
if(j<weight[i]){
m[i][j]=m[i-1][j];
}
else{
m[i][j]=max(m[i-1][j],value[i]+m[i-1][j-weight[i]]);
#include <bits/stdc++.h>
using namespace std;
const int MAX=10000;
int n;//物品的数量
int c;//包的容量
int value[MAX];//物品的价值
int weight[MAX];//物品的重量
int m[MAX][MAX];//求解
int main(){
cin>>n>>c;
for(int i=1;i<=n;i++){
cin>>value[i]>>weight[i];//输入商品的重量和价值
}
memset(m,0,sizeof(m));//初始化为0;
for(int i=1;i<=n;i++){
for(int j=1;j<=c;j++){
//状态转移方程
if(j<weight[i]){
m[i][j]=m[i-1][j];
}
else{
m[i][j]=max(m[i-1][j],value[i]+m[i-1][j-weight[i]]);
}
}
}
cout<<m[n][c];//输出最终值
}
6.最大字段和
给定n个元素的整数列,找到其中字段,使得其和最大
状态转移方程
dp[i]=max(a[i],dp[i-1]+a[i]);
#include <bits/stdc++.h>
using namespace std;
int mian(){
int n;
int a[100]={0};
int dp[100]={0};
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;i<n;i++){
dp[i]=max(a[i],dp[i-1]+a[i]);
}
int k=0;
for(int i=1;i<n;i++){
if(dp[i]>dp[k]){
k=i;
}
}
cout<<dp[k];
return 0;
}