1. 斐波那契数列
int dp[maxn];
int F(int n){
if(n == 0 || n == 1) return 1;
if(dp[n] != -1) return dp[n];
else{
dp[n] = F(n-1) + F(n-2);
return dp[n];
}
}
2. 重叠子问题:
如果一个问题可以被分解为若干个子问题,且这些子问题会重复出现,那么称这个问题拥有重叠子问题。
3. 数塔问题
有形如下图所示的数塔,从顶部出发,在每一结点可以选择向左走或是向右走,一直走到底层,要求找出一条路径,使路径上的值最大。
从顶点出发时到底是向左走还是向右走应取决于向左走能取得最大值还是向右走能取得最大值,只有两条路径上的最大值求出来了才能做出决策,
即dp[1][1] = max(dp[2][1],dp[2][2])
故由此推得状态转移方程为dp[i] = max(dp[i+1][j],dp[i+1][j+1]);
边界条件即最后一层的dp值总是等于元素本身。
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1000;
int dp[maxn][maxn],f[maxn][maxn];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
scanf("%d",&f[i][j]); //输入数塔
}
}
for(int j=1;j<=n;j++){ //边界给dp赋值
dp[n][j] = f[n][j];
}
//从n-1层不断往上计算出dp[i][j]
for(int i=n-1;i>=1;i++){
for(int j=1;j<=i;j++){
dp[i][j]=max(dp[i+1][j],dp[i+1][j+1]) + f[i][j];
}
}
printf("%d\n",dp[1][1]);
return 0;
}
4. 最优子结构:
如果一个问题的最优解可以由其子问题的最优解有效地构造出来,那么称这个问题拥有最优子结构。
一个问题必须拥有重叠子问题和最优子结构,才能使用动态规划去解决。
5. 分治与动态规划
它们都是将问题分解为子问题解决。但分治法分解出的子问题是不重叠的,而动态规划解决的问题拥有重叠子问题
6.最大连续子序列和
(1)dp[i] : 以A[i]作为末尾的连续子序列的最大和
(2)最大连续子序列和就是dp[i]中的最大值
(3)子序列 <1> 只有 i 这一个元素 <2> dp[ i - 1 ] + A [ i ]
状态转换方程:dp[ i ] = max{ A [ i ] ,dp[ i -1] + A[ i ]}
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1000;
int dp[maxn],A[maxn];
int main(){
int n,k=0;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&A[i]);
}
//边界
dp[0] = A[0];
for(int i=0;i<n;i++){
dp[i]=max(A[i],dp[i-1]+A[i]);
}
for(int i=1;i<n;i++){ //找最大值
if(dp[i]>dp[k]) k=i;
}
printf("%d\n",dp[k]);
return 0;
}
如何设计状态和状态转移方程,才是动态规划的核心