动态规划专题总结!

        经过三个星期的学习,基本上了解了ACM中难度最高的 动态规划(DP),整体上对它有了大体的认识,克服了它,就回发现收获很多!!还是需要多看题,多做题!!下面,对动态规划的知识点进行一个总结:

  1.动态规划是一种解决多阶段决策问题的方法!而不是一种特殊的算法!

  2.多阶段决策问题:

   2.1多阶段决策问题:如果一类问题的求解过程可以分为若干个互相联系的阶段,在每一个阶段都需作出决策,并影响到下一个阶段的决策。
   2.2多阶段决策问题,就是要在可以选择的那些策略中间,选取一个最优策略,使在预定的标准下达到最好的效果.

  3.最优性原理:

   3.1不论初始状态和第一步决策是什么,余下的决策相对于前一次决策所产生的新状态,构成一个最优决策序列。
   3.2最优决策序列的子序列,一定是局部最优决策子序列。
   3.3包含有非局部最优的决策子序列,一定不是最优决策序列。

  4.指导思想:
   4.1在做每一步决策时,列出各种可能的局部解
   4.2依据某种判定条件,舍弃那些肯定不能得到最优解的局部解。
   4.3以每一步都是最优的来保证全局是最优的。

  5.动态规划的基本模型:
   5.1动态规划问题具有以下基本特征: 
   5.2问题具有多阶段决策的特征。
   5.3每一阶段都有相应的“状态”与之对应,描述状态的量称为“状态变量”。
   5.4每一阶段都面临一个决策,选择不同的决策将会导致下一阶段不同的状态。
   5.5每一阶段的最优解问题可以递归地归结为下一阶段各个可能状态的最优解问题,各子问题与原问题具有完全相同的结构。

  6.dp的几个概念:
   6.1阶段:据空间顺序或时间顺序对问题的求解划分阶段。
   6.2状态:描述事物的性质,不同事物有不同的性质,因而用不同的状态来刻画。对问题的求解状态的描述是分阶段的。
   6.3决策:根据题意要求,对每个阶段所做出的某种选择性操作。
   6.4状态转移方程:用数学公式描述与阶段相关的状态间的演变规律。

  7.解题步骤:
   7.1判断问题是否具有最优子结构性质,若不具备则不能用动态规划。
   7.2把问题分成若干个子问题(分阶段)。
   7.3建立状态转移方程(递推公式)。
   7.4找出边界条件。
   7.5将已知边界值带入方程。
   7.6递推求解。

   简言之,能用动态和规划解决的问题需要有最优子结构,也就是大问题可以拆成一些小问题,这些小问题和大问题的形式基本是一样的,然后我们在循环中不断更新这些小问题的结果,用数组记录下来,一直到最终的问题时我们直接到数组中取值就可以了。实际上动态规划就是这样子,做题的过程中发现其实子问题很好找的,把问题规模降低子问题就找到了。

最难得其实是状态转移方程,这个一般是挺难找的,我感觉还是从问题的最终目的去考虑方案,比如我们看看到最终的目的有几条路径,这是关键,因为子问题的结构和大问题是一样的。我们只要找到大问题的路径,状态转移方程就找到了。总之,最难找的和最关键的就是状态转移方程!

类型:

  1、编号长度动态规划!

  共性总结:本类的状态是基础的基础,大部分的动态规划都要用到它,成为一个维。

一般来说,有两种编号的状态:

状态(i)表示前i个元素决策组成的一个状态。

状态(i)表示用到了第i个元素,和其他在1到i-1间的元素,决策组成有的一个状态。

  最长上升子序列:

    用数组a存放数字,用dp存放数字状态,即到当前数为止最大的子串长度,用Max找到当前数之前的且小于当前数的最大子序列长度,加 上当前数字原本状态(dp[i]),就是dp[i],也就是新状态

细节处理:

对dp[i]赋初值1。最后用循环找出dp中最大值输出


#include<iostream>
using namespace std;
int main()
{
	int n,i;
	cin>>n;
	int a[1009];
	int dp[1009];
	for(i=1;i<=n;i++)
	{cin>>a[i];dp[i]=1;}
	int j,max;
	for(i=2;i<=n;i++)
	{
		max=0;
		for(j=1;j<i;j++)
		{
			if(a[j]<a[i]&&max<dp[j])
			max=dp[j];
		}
		dp[i]+=max;
	}
	max=0;
	for(i=1;i<=n;i++)
	{
		if(max<dp[i])
		max=dp[i];
	}
	cout<<max;
	return 0;
}

  2利用动态规划思想求最值

共性总结:要利用上次的一些运算“剩下”的循环变量作当前循环的边界,主要在于找出一种决策顺序,使之成立。

  3数轴动态规划问题,01背包问题!

  4集合动态规划(状态压缩)总结

1)数据特殊性
给出的数据在某一个或几个维度上一般具有比较小的范围(可以枚举一类的状态)。一个枚举的状态是一个集合。
2)编码
由于集合中元素个数的不定性或范围大,直接开数组存,不好索引数组(编程复杂度太高),所以要将集合编码。
利用数据的可枚举性,将枚举的状态(集合)编码。一般来说码值的范围要很小
规定编码的码值代表的意思,要尽量规定好维护的码值。
有时候可以直接利用编码的顺序动态规划,因为这时编码已经是拓补有序

  5路径问题:共性总结
a)行走方向决定阶段性
有规定源点与终点。每次行走方向都有一定的规定,使原点到终点的所有路径形成无环有向图。
b双向动态规划
由于有规定源点与终点,可以双向动态规划,但要考虑效果好不好,理论上是比原来少1/2,但有时由于可用于决策的状态较少,效果就不错了。

例题:

三角形最佳路径:

#include<iostream>
using namespace std;
int main()
{
	int n,i,j,max;
	int a[101][101]={0};
	cin>>n;
	for(i=1;i<=n;i++)
		for(j=1;j<=i;j++)
		cin>>a[i][j];
	for(i=n-1;i>=1;i--)
	{
		for(j=1;j<=i;j++)
		{
			max=a[i+1][j]>a[i+1][j+1]?a[i+1][j]:a[i+1][j+1];
			a[i][j]+=max;
		}
	}
	cout<<a[1][1];
	return 0;
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值