动态规划 DP 及 使用,数塔问题,斐波那契数列,最大连续子序列和

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;
 } 

如何设计状态和状态转移方程,才是动态规划的核心

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值