五大算法之动态规划 (经典问题)

动态规划
  • 核心
    状态转移方程

  • 特性
    最优化子问题: 将复杂的问题分解为若干个子问题,然后综合子问题的最优解来得到原问题的最优解
    重叠子问题: 一些问题可以被分解为若干子问题,且这些子问题会重复出现
    无后效性:当前状态记录了历史信息,一旦当前状态确定,就不会在改变,且未来的决策只能在已有的一个或若干个状态的基础上进行,历史状态只能通过已有的信息去影响未来

  1. 递归写法
    以斐波那契举例
    若直接暴力求解,时间复杂度为O(2^n)
// n为输入的斐波那契数列第n项
int f(int n)
{
	if(n==0||n==1) return 1;
	else return f(n-1)+f(n-2);
} 
 

递归写法也称为记忆化搜索

// 设置dp数组存储
const int maxn=1000;
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];
	}
} 

  1. 递推写法
    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 i=n-1;i>=i;--i)
	{
		dp[n][i]=f[n][i];
	} 
	
	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;	
} 
//输入样例
5
5
8 3
12  7 16
4 10 11 6
9 5 3 9 4

以下例子中:细节说明求解动态规划的方法

1. 最大连续子序列和
给定一个数字序列a1,a2,a3,…,求i,j(1<=i<=j<=n),使得ai+…a j(连续的)最大,输出这个最大和

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

const int maxn=10000+10;
int a[maxn],dp[maxn];
int main()
{
	   freopen("C:\\Users\\24398\\Desktop\\in-project.txt","r",stdin);
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;++i)
	{
		scanf("%d",&a[i]);
	}
	// 边界
	dp[0]=a[0];
	for(int i=1;i<n;++i)
	{
		//状态转移方程
		dp[i]=max(a[i],dp[i-1]+a[i]); 
	}
	sort(dp,dp+n);
	cout<<dp[n-1]<<endl; 
	return 0;
}
//输出示例
5 
1 2 -4 5 3 
//输出
8

2. 最长不下降子序列
在一个数字序列中,找到一个最长的子序列(可以不连续),使得这个子序列是下降的(非递减的)

#include<cstdio>
#include<algorithm>
#include<iostream> 
using namespace std;

const int n=100;
int a[n],dp[n];
int main()
{
	int n;  cin>>n;
	for(int i=0;i<n;++i)
	{
		cin>>a[i];
	}
	int ans=0;  //记录
	for(int i=1;i<=n-1;++i)
	{
		dp[i]=1;
		for(int j=1;j<i;++j){
			if(a[i]>=a[j]&&(dp[j]+1>dp[i])){
				dp[i]=dp[j]+1;
			}
		}
		ans=max(ans,dp[i]);
	} 
	cout<<ans<<endl;
	return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值