第十一章 动态程序设计方法
- 格式:doc
- 大小:490.00 KB
- 文档页数:24
c程序设计教程郑阿奇C程序设计教程是计算机科学与技术领域中一门重要的课程,它不仅为学生提供了编程的基本技能,还为进一步学习高级编程语言和软件开发奠定了基础。
本教程由郑阿奇教授编写,旨在通过系统的教学和实践,帮助学生掌握C语言的基本知识和应用技巧。
第一章:C语言概述C语言是一种通用的编程语言,由丹尼斯·里奇在1972年开发,用于UNIX操作系统。
C语言以其高效性、灵活性和可移植性而闻名,是许多现代编程语言的基石。
第二章:C语言基础本章将介绍C语言的基本语法,包括变量、数据类型、运算符和表达式。
学生将学习如何声明变量、进行算术运算和逻辑运算。
第三章:控制结构控制结构是程序设计中的核心,包括条件语句(if、switch)和循环语句(for、while、do-while)。
本章将详细讲解这些控制结构的使用方法和逻辑。
第四章:函数函数是C语言中实现代码复用和模块化的重要手段。
本章将教授如何定义函数、调用函数以及如何使用函数参数和返回值。
第五章:数组和字符串数组是存储固定大小元素集合的数据结构,而字符串是特殊的字符数组。
本章将介绍数组的声明、初始化和访问,以及字符串处理函数的使用。
第六章:指针指针是C语言中一个强大的特性,它允许直接操作内存地址。
本章将讲解指针的基本概念、指针与数组的关系以及指针在函数中的应用。
第七章:结构体和联合体结构体和联合体是C语言中用于创建复杂数据类型的复合数据结构。
本章将介绍如何定义和使用这些数据结构,以及它们在程序设计中的作用。
第八章:预处理器预处理器是C语言编译过程中的一个阶段,它处理源代码中的宏定义、文件包含和条件编译等指令。
本章将介绍预处理器的基本概念和用法。
第九章:文件操作文件操作是程序与外部数据交互的重要方式。
本章将讲解如何在C语言中打开、读取、写入和关闭文件。
第十章:动态内存分配动态内存分配允许程序在运行时申请和释放内存。
本章将介绍malloc、calloc、realloc和free等函数的使用方法。
第十一章自动编程如何进行数控加工程序的编制是进行数控加工的关键,传统的手工编程方法复杂、繁琐,易于出错,难于检查,不能充分发挥数控加工的优势。
尤其对某些形状复杂的零件,如自由曲面零件的编程问题,手工编程是根本无法实现的。
所以,手工编程一般只用在形状简单的零件加工中,而对于形状复杂的零件,则需要用计算机进行辅助处理和计算。
第一节自动编程概述一、自动编程的基本原理手工编程中的几何计算、编写加工程序单、程序校核,甚至工艺处理等由计算机自动处理完编程”,简称“自动编程”。
自动编程是通过数控自动程序编制系统实现的。
它包括硬件及软件两部分,硬件主要由计算机及绘图仪、扫描仪等一些外围设备组成;软件即计算机编程系统,又称编译软件,它主要作用是使计算机具有处理工件源程序并自动输出具体数控机床加工程序的能力。
图11-1 自动编程的工作过程自动编程的工作过程如图11-1所示。
1.准备原始数据自动编程系统不会自动地编制出完美的数控程序。
首先,人们必须给计算机送入必要的原始数据,这些原始数据描述了被加工零件的所有信息,包括零件的几何形状、尺寸和几何要素之间的相互关系,刀具运动轨迹和工艺参数等等。
原始数据的表现形式随着自动编程技术的发展越来越多样化,它可以是用数控语言编写的零件源程序,也可以是零件的图形信息,还可以是操作者发出的声音等等。
一些原始数据是由人工准备的,当然它比直接编制数控程序要简单、方便得多。
2.输入翻译原始数据以某种方式输入计算机后,计算机并不立即识别处理,必须通过一套预先存放在计算机中的编程系统软件,将它翻译成计算机能够识别和处理的形式。
由于它的翻译功能,故又称编译软件。
计算机编程系统品种繁多,原始数据的输入方式不同,程编系统就不一样,即使是同一种输入方式,也有很多种不同的程编系统。
3.数学处理这部分是根据已经翻译的原始数据计算出刀具相对于工件的运动轨迹。
编译和计算合称为前置处理。
4.后置处理后置处理就是编程系统将前置处理的结果处理成具体的数控机床所需要的输入信息,即形成了零件加工的数控程序。
c程序设计教程谭浩强第三版C程序设计教程是谭浩强教授编写的一本广受欢迎的C语言学习教材。
第三版在前两版的基础上做了进一步的修订和完善,更加适合初学者和中级学习者使用。
本教程涵盖了C语言的基础知识、语法规则、程序设计技巧以及一些高级主题。
以下是对这本教程的详细内容概述。
第一章:C语言概述本章介绍了C语言的发展历程、特点和应用领域,让读者对C语言有一个整体的认识。
同时,也介绍了C语言程序的基本结构和编译、链接过程。
第二章:数据类型、运算符和表达式这一章详细讲述了C语言中的基本数据类型,包括整型、浮点型、字符型等,以及它们在内存中的存储方式。
此外,还介绍了各种运算符的用法和优先级,以及如何构建表达式。
第三章:控制语句控制语句是程序设计中非常重要的部分,本章讲解了条件语句(if、switch)、循环语句(for、while、do-while)以及跳转语句(break、continue、goto)的用法和应用场景。
第四章:数组数组是C语言中一种基本的数据结构,用于存储具有相同类型的多个数据项。
本章介绍了一维数组和二维数组的声明、初始化和访问方法。
第五章:指针指针是C语言的核心概念之一,本章深入讲解了指针的基本概念、指针与数组的关系、指针的运算以及指针在函数中的应用。
第六章:函数函数是程序模块化的基础,本章介绍了函数的定义、声明、调用以及参数传递机制。
同时,也讨论了递归函数和内联函数的概念。
第七章:预处理指令预处理指令是C语言编译过程中的指令,用于在编译前对源代码进行处理。
本章介绍了宏定义、文件包含、条件编译等预处理指令的用法。
第八章:结构体和联合体结构体和联合体是C语言中用于创建复杂数据类型的工具。
本章讲解了它们的声明、初始化以及在程序中的应用。
第九章:位运算位运算是直接对数据的二进制位进行操作的运算。
本章介绍了位运算符的用法和一些常见的位运算技巧。
第十章:文件操作文件操作是程序与外部数据交互的重要方式。
书名:公共行政学主编:许才明出版社:人民邮电出版社出版时间:2010年7月本书资料:提供多媒体课件、电子教案、习题答案及案例分析等材料,需要者可发邮件至wanguoqingljw@索取第11章习题答案及案例分析一、名词解释1.行政决策所谓行政决策,是指行政机关为履行行政职能所作的行为设计和抉择过程。
2.非程序性决策所谓非程序性决策,是指新出现的具有大量不确定因素,缺乏可靠数据、资料,无常规可循,必须进行专门研究的决策。
它一般是由高层次的领导做出,用于解决行政活动中复杂而重要的事情。
3.风险型决策所谓风险型决策,又称随机决策或统计型决策,是指行政决策的条件、因素可以确定,但不能控制后果且要承担一定风险的决策。
二、判断说明题1.不确定型决策是指行政决策的条件、因素可以确定,但不能控制后果且要承担一定风险的决策。
参考答案:错误;不确定性决策是指决策条件、因素不确定,完全不能控制,决策后果难以预料,也就是这些方案的可能性结果在过去的实践中从未出现,决策者也没有任何这方面的经验,而完全根据主观判断或推测计算出概率(即计算出可能性的大小)后进行决策。
上文中描述的应该是风险型决策。
2.现代行政决策体制的核心是行政决策信息系统。
参考答案:错误;现代行政决策体制的核心是行政决策中枢系统。
三、简答题1.简述行政决策的类型。
参考要点:1)程序化决策和非程序化决策2)战略性决策和战术性决策3)经验决策和科学决策4)高层决策、中层决策与基层决策5)确定型决策、风险型决策和不确定型决策2.简述行政决策的基本原则。
参考要点:1)信息准、全、新原则2)系统分析原则3)可行性原则4)动态可变原则5)科学民主原则6)对比选优原则7)时效原则3.简述行政决策的基本程序及方法。
参考要点:1)行政决策的基本程序:调查研究,发现问题,确定目标;科学设计,拟定方案;综合评价,选择最佳方案;实施检验,调整完善。
2)行政决策的基本方法:科学决策法;渐进决策法;远近结合法。
第十一章 动态程序设计方法在现实生活中,有一类活动的过程,由于它的特殊性,可将过程分成若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果。
当然,各个阶段决策的选取不是任何确定的,它依赖于当前面临的状态,又影响以后的发展,当各个阶段决策确定后,就组成一个决策序列,因而也就确定了整个过程的一条活动路线(图11.1.1)。
这种把一个问题看作是一个前后关联具有链状结构的多阶段过程就称为多阶段决策过程,这种问题就称为多阶段决策问题。
图11.1.1在多阶段决策问题中,各个阶段采取的决策,一般来说是与时间有关的,决策依赖于当前状态,又随即引起状态的转移,一个决策序列就是在变化的状态中产生出来的,故有“动态”的含义,我们称这种解决多阶段决策最优化的过程为动态程序设计方法。
应当指出,动态程序设计方法是考察求解多阶段决策问题的一种途径、一种方法,而不是一种特殊算法。
不象前面所述的那些解析法或搜索法那样,具有一个标准的数学表达式和明确定义的一组规划。
因此读者在学习时,除了要对基本概念和方法正确理解外,必须具体问题具体分析处理,以丰富的想象力去建立模型,用创造性的技巧去求解。
§11.1 基本概念我们先引入动态程序设计的一些概念、术语和符号: 1. 阶段k一个实际问题可能要有多次决策。
为此对整个问题,可按其特点划分成需要作出选择的若干轮次。
这些轮次即称为阶段。
阶段是前后关联的。
我们从第1个阶段开始,按照阶段的先后顺序进行决策。
2. 状态u k某一阶段的出发位置称为状态,通常一个阶段包含若干状态,因此u k 是一个状态集。
我们将始点至k 阶段的u k ’(u k ’∈u k )状态所获得的最小费用设为I[u k ’]。
设初始状态为u 0’。
显然初始时,对所有状态u 来说 ⎪⎩⎪⎨⎧≠∞==0'0][u u u u u I3. 决策x k在对问题的处理中作出的每种选择性的行动就是决策,即从该阶段的每一个状态出发,通过一次选择性的行动转移至下一阶段的相应状态。
一般来说,可供选择的决策不止一个,组成一个决策集x k 。
每作出一种决策需要花费代价。
我们设k 阶段的u k ’状态选择决策x k ’(x k ’∈x k )的直接费用为l[u k ’,x k ’]。
4. 按照最优解的结构递归定义状态转移方程前一阶段的终点就是后一阶段的起点,对前一阶段的状态作出某决策产生后一阶段的状态,这种关系描述了由k 阶段到k+1阶段状态的演变规律,称为状态转移方程。
按照最优解的结构,状态转移方程的一般形式为I[u k ’]=1111''max)min(----∈∈k k k k x x u u 或{I[u k-1’]+L[u k-1’,x k-1’]|k-1阶段的状态u k-1’通过x k-1’决策可达k 阶段的u k ’}5. 适用动态程序设计方法求解的问题特征适用动态程序设计方法求解的问题一般具有下述特征::①满足最优子结构的性质。
从上式中可以看出,要使得I[u k ’]最小,则I[u k-1’]必须最小。
为什么?如果初始状态至u k-1’有一个费用更小的方案,那么将其替换至上式中,就会使得I[u k ’]更小,出现矛盾。
因此该问题具备了最优子结构的性质。
采用动态程序设计方法求解的第一个前提是问题必须具备最优子结构的性质。
有些问题的求解过程可以划分阶段,但不具备最优子结构。
例如“§10.2回溯法”的【例五】。
如果不允许重复挖地雷的话,问题则呈现出阶段性。
设阶段j :步数(1≤j ≤n );状态k :第j 步经过地窖k (1≤k ≤n );决策a :第j-1步经过地窖a 可使得第j 步经过地窖k 所能挖到的地雷数最多(1≤a ≤n ); f[i ,k]—第i 步经过地窖k 所能挖到的最多地雷数;w[i ,k]—第i 步经过地窖k 的最佳路径; (1≤i ,k ≤n ) best —所能挖到的最多地雷数; 状态转移方程如下:f[i ,k]=k}a ,),(,0],1[],1[{max 1的路径上未出现通往地窖的地雷数G k a a i f k a i f na ∈≠-+-≤≤。
若满足条件,则通过w[i ,k]=w[i-1,a]+{k}记下路径。
初始时f[1,i]=i 地窖的地雷数;w[1,i]={i}然后按照阶段的顺序递推。
挖第i 步时依据下式计算所能挖到的最多地雷数best=k}a ,),(,0],1[],1[{max 1的路径上未出现通往地窖的地雷数G k a a i f k a i f na ∈≠-+-≤≤若满足条件,则w[i ,k]=w[i-1,a]+{k}。
经过n 个阶段后得出的best 即为解。
从表面上看,该问题具备了最优子结构的性质,其实不然。
例如图11.1.1为地窖间的相连情况。
○左方的数字为地窖序号,○内的数字为地雷数:图11.1.1按照状态转移方程可以得出表11.1.1(f 数组)和表11.1.2(w 数组):表11.1.1表11.1.2由此可见,在出现回路的情况下,该问题不具备最优子结构的性质,误用动态程序设计方法求解会导致错误结论。
②满足重迭子问题的性质。
在k-1阶段通过决策集x k-1可达u k ’的状态u k-1’可能不止一个,因此必须一一查阅这些子问题的最优解I[u k-1’](u k-1’∈u k-1),即该问题又同时具备了重迭子问题的性质。
这是采用动态程序设计方法求解的第二个前提。
如果在计算最佳值的过程只不需要回头查阅子问题的最优解(即求解策略中不含比较所有子问题解的过程),则可以采用递推法或贪心法求解。
③求解过程具有阶段性的特征从初始状态出发,按照上式逐个阶段地计算每一个状态的最优解,直至最后阶段的目标状态的最优解求出为止。
6.可以借助动态程序设计方法求解的一些问题对于一些虽然阶段性和状态转移关系明显、但不具备最优子结构特征或不属于最优化的问题,是否也可以借助动态程序设计方法呢?下面提供一些思路: ①如果在状态转移方程I[u k ’]=1111''max)min(----∈∈k k k k x x u u 或{I[u k-1’]+L[u k-1’,x k-1’]|k-1阶段的状态u k-1’通过x k-1’决策可达k 阶段的u k ’}中去掉最佳性要求(min 或max ),将扩展子状态的所有行动作为决策,则可以例举出由初始状态至u k ’的所有方案。
显然,在计数类问题中使用这种方法要比回溯法等搜索算法简捷许多(如【例题11.2.1】、【例题11.2.2】、【例题11.2.3】)。
②对于一些阶段性明显、但不具备最优子结构特征的问题,可以考虑将指标函数值当作“状态”,从而变最优化问题为判定性问题。
再借用动态程序设计思想,用递推方式计算最佳值(如【例题11.2.4】)。
§11.2 程序流程的一般形式从阶段1出发,依次枚举各个阶段的所有状态,将每个子问题代入状态转移方程计算一次,充分利用重迭子问题。
由于这种方式无需递归代价,因此其效率好于自上而下的求解方式。
按照阶段、状态和决策的层次关系,我们给出程序流程的一般形式:所有状态u 的最小费用初始化:⎩⎨⎧≠∞==00'0][u u u u u I ;for k ;=阶段最小值to 阶段最大值do {顺推每一个阶段} for u ;=状态最小值to 状态最大值do {枚举阶段k 的每一个状态} for x ;=决策最小值to 决策最大值do {枚举阶段k 中状态u 可选择的每一种决策} begini[u k ’]←min{i[u k-1’]+L[u k-1’,x k-1’]|u k-1’通过决策x k-1’可达u k ’} end ;{for}这里需要说明的是,上述程序流程仅是提供了自下而上方式解题的一种思路或方法,并不是说所有按自下而上方式解题的程序流程都应如此。
例如1.若状态非一个整数值所能描述(例如代表平面或空间上的一个坐标),则枚举状态的第二重循环可由相应的多重循环替代(如【例题11.2.8】);2.若每一个阶段仅一个出发位置,则可通过一重循环枚举各个阶段的状态(如【例题11.2.1】、【例题11.2.5】);3.如果可供选择的决策较少或者较难定义决策序号,则取消枚举决策的第三重循环,将决策过程直接放入状态转移方程或者在循环体内编写决策选择程序;我们必须从问题本身和解题需求出发,具体问题具体分析,制定行之有效的策略。
【例题11.2.1】骑士游历问题(2)设有一个n*m的棋盘(2≤n≤50,2≤m≤50),如图11.2.1。
在棋盘上任一点有一个中国象棋马,图11.2.1马走的规则为:1.马走日字2.马只能向右走。
即图11.2.2所示:图11.2.2当N,M 给出之后,同时给出马起始的位置和终点的位置,试找出从起点到终点的所有路径的数目。
例如:(N=10,M=10),(1,5)(起点),(3,5)(终点)。
应输出2(即由(1,5)到(3,5)共有2条路径,如图11.2.3):图11.2.3输入:n,m,x1,y1,x2,y2(分别表示n,m,起点坐标,终点坐标)输出:路径数目(若不存在从起点到终点的路径,输出0)题解由【例题10.2.1】骑士游历问题(1)看出,使用回溯法同样可以计算路径数目。
只要将起点(1,1)和终点(n,m)调整为(x1,y1)、(x2,y2),并在回溯程序(search(k,x,y))中,将马跳到目的地时由退出程序(halt)改为回溯(exit)即可。
但问题是搜索效率太低,根本不可能在较短的时间内出解。
本题与【例题10.2.1】骑士游历问题(1)不同,并不要求每一条路径的具体走法。
在这种情况下,是否非得通过枚举所有路径方案后才能得出路径数目,有没有一条简便和快效的“捷径”呢。
从(x1,y1)出发,按照由左而右的顺序定义阶段的方向。
位于(x,y)左方且可达(x,y)的跳马位置集合都是(x,y)的子问题,起点至(x,y)的路径数实际上等于起点至这些位置集的路径数之和(图11.2.4)。
图11.2.4如此一来,状态转移关系便凸显出来。
设状态转移方程map ,其中map[i ,j]为起点(x1,y1)至(i ,j )的路径数目。
由于棋盘规模的上限为50*50,可能导致路径数目大得惊人,因此不妨设map 数组的元素类型为extended 。
初始时,除map[x1,y1]=1外其余为0。
显然}),(],[],[{],[),),(在界内的坐标集可达(y x y x map j i map y x map y x j i ∑∈+=。
我们采用动态程序设计的方法计算起点(x1,y1)至终点(x2,y2)的路径数目map[x2,y2]:阶段j :中国象棋马当前的列位置(y 1≤j ≤y2); 状态i :中国象棋马在j 列的行位置(1≤i ≤n );决策k :中国象棋马在(i ,j )的起跳方向(1≤k ≤4); 计算过程如下:fillchar(map ,sizeof(map),0); map[x1,y1] ←1; {从(x1,y1)出发} for j ←y1 to y2 do {递推中国象棋马的列位置} for i ←1 to n do {递推中国象棋马在j 列的行位置} for k ←1 to 4 do {递推中国象棋马在(i ,j )的4个跳动方向} begin 中国象棋马由(i ,j )出发,沿着k 方向跳至(x ,y );if (x ∈{1..n })∧(y ∈{1..y2}) {计算状态转移方程}then map[x ,y] ←map[i ,j]+map[x ,y]end ;{for}writeln(map[x2,y2]:0:0); {输出从(x1,y1)到(x2,y2)的路径数目}【例题11.2.2】砝码称重设有1g ,2g ,3g ,5g ,10g ,20g 的砝码各若干枚(其总重≤1000g ),要求: 输入:a1 a2 a3 a4 a5 a6(表示1g 砝码有a1个,2g 砝码有a2个,......20g 砝码有a6个) 输出:Total=N (N 表示用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况) 输入样例:1 1 0 0 0 0输出样例:Total=3,表示可以称出1g ,2g ,3g 三种不同的重量题解设const num :array[1..6] of shortint=(1,2,3,5,10,20); {砝码的重量序列} vara :array[1..6] of integer ; {6种砝码的个数} visited :array[0..1000] of boolean ; {重量的访问标志序列} no :array[0..1000] of integer ; {n0[0]—不同重量数;n0[j]—第j 种重量(1≤j ≤no[0])} total ,i ,j ,k :integer ; {total —目前称出的重量}我们按照第1种砝码,第2种砝码,……第6种砝码的顺序分析。