动态规划1

1,什么是动态规划(DP)?
 
只有对概念理解深刻,才能准确知道对于什么样的问题去考虑有没有动态规划的方法,以及如何去使用动态规划	1)动态规划是运筹学中用于求解决策过程中的最优化数学方法。多阶段决策过程中最优的通用方法。
	它是数学中用于求解某类最优化问题的重要工具。
 
	2)如果问题是由“交叠的子问题”构成,我们就可以用动态规划技术来解决,一般来说,这样的子问题出现在对给定问题求解的“递推关系”中,这个递推关系包含了相同问题的更小子问题的解。

	动态规划建议:与其对交叠子问题反复求解,不如把每个较小子问题只求一次并把结果记录在表中(空间换时间),这样就可以从表中得到原始问题的解。
 
关键描述:
	往往是解决最优化的问题
	问题表现为多阶段决策
多阶段决策过程:过程可以按时间顺序分解成若干个阶段,在每一个阶段都需要做出决策,全部过程的决策是一个决策序列。
交叠子问题
 
	动态规划思想:记忆、空间换时间、不重复求解、由交叠子问题从较小问题逐步决策-à构造大问题的解
 
 
 
	般来说,一个经典的动态规划算法时自底向上的(从较小问题的解,由交叠性质,逐步决策处较大问题的解),它需要解出给定问题的所有较小子问题。动态规划的一个变种是试图避免对不必要的子问题求解。如果采用自顶向下的递归来解,那么就避免了不必要子问题的求解(相对于动态规划表现出优势),然而递归又会导致对同一个子问题多次求解(相对于动态规划表现出劣势),所以将递归和动态规划结合起来,就可以设计一种基于记忆功能的从顶向下的动态规划算法
 
计算二项式系数:
在排列组合里面,我们有下面的式子(很容易用组合的定义来证明):
C(n,k)=C(n-1,k-1)+C(n-1,k)

这个式子将C(n, k)的计算问题表述为了(问题描述)C(n-1 , k -1)和C(n -1, k)两个较小的交叠子问题。
初始条件:C(n , n) = C(n , 0) = 1
我们可以用下列填矩阵的方式求出C(n , k):
 

该算法的时间复杂度是多少呢?可以大概的估计下,只填了下三角矩阵,为n*k/2  =  n*k,具体的次数为:

算法Binomial(n,k);    伪代码
       //动态规划计算C(n,k)
       //输入:一对整数n>=k>=0
       //输出C(n,k)的值
       for i<- 0 to n do
              fo j<-0 to min(i,k) do
                     if j=0 or j=i
                     C[I,j]<-1
			else C[I,j]<-C[i-1,j-1]+C[i-1,j]
     		  return C[n,k];
第1个for是控制行的,要填到第n行。第2个for来控制每行填到哪的,到i和k的较小值。从这2个for也可以看出复杂度是n*k。
 
#include<iostream>
using namespace std;
intbinomial(int,int);
int min(int ,int);
int main()
       {
       int n,k,i;
       while(cin>>n>>k)
              {
              for(i=0;i<=n;i++)
                     cout<<binomial(n,i)<<endl;
              }
       return 0;
       }
int binomial(intn,int k)
       {
       //计算二次项系数C(n,k)
              int i,j;
              int **result=new int*[n];
              for(i=0;i<=n;++i)
                     result[i]=new int[n];
              for(i=0;i<=n;++i)   //按行
                     for(j=0;j<=min(i,k);++j)  //列数
              {
                     if(j==0||i==j)
                            result[i][j]=1;
                     else
                            result[i][j]=result[i-1][j-1]+result[i-1][j];
              }
              return result[n][k];
       }
int min(int a,int b)
       {
       if(a<b) return a;
       else
              return b;
       }

 
再看动态规划:
1、怎么描述问题,要把问题描述为交叠的子问题。
2、交叠子问题的初始条件(边界条件)
3、动态规划在形式上往往表现为填矩阵的形式。(在后面会看到,有的可以优化空间复杂度,开一个数组即可,优化也是根据递推式的依赖形式的,后面有篇文章详细说明)
4、填矩阵的方式(或者顺序说明了什么)?  表明了动态规划是从小到大产生的过程,专业点的说就是 递推式的依赖形式决定了填矩阵的顺序
 
习题:
1、动态规划和分治法的相同和不同点,
相同:都把问题划分为了较小规模问题的解
不同:动态规划较小子问题是交叠的,而且要存储较小子问题的解
 
2、a,计算C(n,k)的动态规划算法—Binomial算法的空间效率\b,及是否可以改进算法空间效率
a, 空间效率也是nk,参见代码,或者从矩阵上也可看出
b,可以,这个问题的表明了再看动态规划第三点(优化空间复杂度)
---为什么可以优化,上面说过,可不可以优化,以及如何优化空间复杂度依赖于它的递推形式:
---从填矩阵的那张图可以看出,这个动态规划产生各项的过程(如果按行填的话)是上一行的第 i-1 项和第 i 项加起来产生下一行的第 i 项,传统上,我们从左往右填。
---事实上,根据它的产生过程(这个产生过程依赖于递推式自身的数学特征),可以从右往左填,这样开一个数组就行,在原数组上本地不动的填数,从右往左填可以保证一个位置在覆盖以后不会再被用到(这是由递推式的属性决定的,需要画一画才看的比较清楚)。这样开一个K大的数组就行了,具体的实现就不写了,已经分析的很清楚了,实现也不难。
 
由以上分析,加习题,相信对于动态规划到底是什么,核心思想,具体的操作细节,以及对于动态规划的理解都加深了吧,
有2点我觉得非常重要,
	一是填矩阵的顺序,
	二是动态规划空间复杂度的优化
	这2点都跟递推式的依赖关系有关(这是本质),在形式上就表现为填矩阵的时候你的顺序要确保每填一个新位置时你所用到的那些位置(即它依赖的)要已经填好了,在空间优化上表现为当一个位置在以后还有用的时候你不能覆盖它。
 
	这2条结论非常重要,是深刻理解动态规划的一个重要阶梯,我也是好久慢慢悟出来的,当然,它们有更professional的表述,在下一篇文章里我会贴出。
 
http://blog.youkuaiyun.com/mengzhejin/article/details/37880413
一、综合实战—使用极轴追踪方式绘制信号灯 实战目标:利用对象捕捉追踪和极轴追踪功能创建信号灯图形 技术要点:结合两种追踪方式实现精确绘图,适用于工程制图中需要精确定位的场景 1. 切换至AutoCAD 操作步骤: 启动AutoCAD 2016软件 打开随书光盘中的素材文件 确认工作空间为"草图与注释"模式 2. 绘图设置 1)草图设置对话框 打开方式:通过"工具→绘图设置"菜单命令 功能定位:该对话框包含捕捉、追踪等核心绘图辅助功能设置 2)对象捕捉设置 关键配置: 启用对象捕捉(F3快捷键) 启用对象捕捉追踪(F11快捷键) 勾选端点、中心、圆心、象限点等常用捕捉模式 追踪原理:命令执行时悬停光标可显示追踪矢量,再次悬停可停止追踪 3)极轴追踪设置 参数设置: 启用极轴追踪功能 设置角度增量为45度 确认后退出对话框 3. 绘制信号灯 1)绘制圆形 执行命令:"绘图→圆→圆心、半径"命令 绘制过程: 使用对象捕捉追踪定位矩形中心作为圆心 输入半径值30并按Enter确认 通过象限点捕捉确保圆形位置准确 2)绘制直线 操作要点: 选择"绘图→直线"命令 捕捉矩形上边中点作为起点 捕捉圆的上象限点作为终点 按Enter结束当前直线命令 重复技巧: 按Enter可重复最近使用的直线命令 通过圆心捕捉和极轴追踪绘制放射状直线 最终形成完整的信号灯指示图案 3)完成绘制 验证要点: 检查所有直线是否准确连接圆心和象限点 确认极轴追踪的45度增量是否体现 保存绘图文件(快捷键Ctrl+S)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值