算法分析大作业动态规划方法解乘法表问题和汽车加油行驶问题#精选.
算法实训-汽车加油问题

一、问题定义【问题描述】一辆汽车加满油后可行驶n公里。
旅途中有若干个加油站。
设计一个有效算法,指出应在哪些加油站停靠加油,使沿途加油次数最少。
【输入输出及示例】输入:第一行有2个正整数n和k(k<=1000),表示汽车加满油后可行驶n公里,且旅途中有k个加油站。
第二行有k+1个整数,表示第k个加油站与第k-1个加油站之间的距离。
第0个加油站表示出发地,汽车已加满油。
第k+1个加油站表示目的地;输出:如果可以到达目的地则输出最少加油次数,及在第多少个加油站加油。
如果无法到达目的地,则输出“NoSolution!”示例:输入:请输入汽车加满油后可行驶公里数及加油站数: 9 7请依次输入加油站间距离:1 2 3 4 5 1 6 6输出:最少加油次数:3次分别在以下加油站加油:第3个, 第5个, 第7个,二、问题分析1.关于输入距离的说明:关于格式的说明,k个加油站,加上起点和终点,共计k+2个停靠点,有k+1个区间(距离),故第k个距离表示第k个加油站与第k-1个加油站之间的距离,如第一个输入距离则为起点与第一个加油站的距离,最后一个距离,则为最后一个加油站与终点的距离,依次类推;如:请输入汽车加满油后可行驶公里数及加油站数: 9 7请依次输入加油站间距离:1 2 3 4 5 1 6 62.求解过程:输入每个加油站之间的距离,然后某两个加油站之间的距离与汽车油箱最大行驶距离进行比较:(1)如果某两个加油站之间的距离大于汽车油箱最大行驶距离,则汽车不可到达目的地。
即:a[i]>n则输出:“NoSolution!”,结束程序,汽车无论如何不能到达目的地;(2)如果某两个加油站之间的距离小于等于汽车油箱最大行驶距离,距离下一个加油站距离大于汽车油箱最大行驶距离,则在此加油站停车,满足贪心选择性质。
使用贪心策略:对当前待行驶的第i段路程(距离),如果不能行驶(距离大于汽车剩余行驶距离),则加满油行驶,如仍然不能正常行驶(即区间距离大于最大行驶距离),宣告失败;否则,加油计数器更新,行驶过第i段;对下一段同样处理。
东北石油大学算法例题

◎【跳台阶问题】一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。求总共有多少种跳法,并分析算法的时间复杂度。
●对于N级台阶,如果第一跳只跳一级,那么还剩下N-1级,如果第一跳只跳两级,那么还剩下N-2级,由此不难得出对于N级的台阶,总的跳法数相当于N-1级与N-2级的跳法数量之和。
当k排在第n位时,除了n和k以外还有n-2个数,其错排数为Dn-2。
当k不排在第n位时,那么将第n位重新考虑成一个新的“第k位”,这时的包括k在内的剩下n-1个数的每一种错排,都等价于只有n-1个数时的错排(只是其中的第k位会换成第n位)。其错排数为Dn-1。所以当n排在第k位时共有Dn-2+Dn-1种错排方法,又k有从1到n-1共n-1种取法,我们可以得到:Dn=(n-1)(Dn-1+Dn-2)。
设n个矩阵的括号化方案的种数为f(n),那么问题的解为
f(n) = f(1)*f(n-1) + f(2)*f(n-2) + f(3)*f(n-3) + f(n-1)*f(1)。f(1)*f(n-1)表示分成(a1)×(a2×a3.....×an)两部分,然后分别括号化。
计算开始几项,f(1) = 1, f(2) = 1, f(3) = 2, f(4) = 5。结合递归式,不难发现f(n)等于h(n-1)。
}
return an;
}
◎【瓷砖覆盖地板】用1*2的瓷砖覆盖2 * m的地板有几种方式?
f(1) = 1;
f(2) = 2;
f(m) = f(m-1) + f(m-2); (m > 2)
◎【买票找零问题】2n个人排队买票,其中n个人持50元,n个人持100元。每张票50元,且一人只买一张票。初始时售票处没有零钱找零。请问这2n个人一共有多少种排队顺序,不至于使售票处找不开钱?
贪心算法-汽车加油问题

int greedy(vector<int>x, int n) { int sum=0;k=x.size(); for(int i=0;i<k;i++) { if(x[i]>n) return -1; } for(int i=0,s=0;i<k;i++) { s+=x[i]; if(s>n) { sum++; s=x[i]; } } return sum; } sum=4;
●问题描述 一辆汽车加满油之后可以行驶n KM ,旅途中有若干个加油站,设 计一个算法指出在哪些加油站停靠加油可以是沿途加油次数最少。 (给定n和k个加油站位置)
7 7 12345166●问题分析 起点 2 3 4 5 1 6 6 终点
假设X[i]表示i-1到i号加油站之间的距离,每一次都是加 满油再出发,根据贪心算法的选择性质为了要使加油次数最少就会 选择离加满油的点远一点的加油站加油。另外当加满油之后,都要 是此后的过程中使加油次数最少,同样,在第二次加满油之后也要 使此后的加油次数最少。每一次汽车中剩下的油不能再行驶到下一 站就在该站加油,每一次加满油之后与起点具有相同的条件,过程 也是相同的。所以说加油次数最少也具有最优子结构的性质。 贪心策略:最远加油站优先。 第一次遍历,主要是看X[i]是否大于n,若大于n是到达不了重点的,错 误。 第二次遍历,给定s表示加满油之后行驶的距离,如果s>n,说明需要加油, 加油次数sum++,s=x[i]。
Thank you !
贪心算法——汽车加油问题
贪心算法基本思想:
贪心算法总是做出在当前看来是最好的选择,并不会从总体去最优考 虑。虽然贪心算法不会对所有问题找到最优,但是有时候会得到最优 解的近似解。
《算法分析与设计》汽车加油问题

汽车加油问题1. 问题描述一辆汽车加油满后可行驶n千米,旅途中有若干加油站(不包含汽车的出发点)。
假如在出发时已加满油,设计一个有效算法,指出应在哪些加油站停靠加油,使沿途加油次数最少,并给出加油的地点。
证明算法能产生一个最优解。
算法设计:对于给定的n和k个加油站位置,计算最少加油次数。
2. 算法流程分析设汽车加满油后可行驶n千米,且除了出发点和目的地,旅途中有k个加油站。
把目的地假设为最后一个加油站,有k个加油站。
令数组x存储加油站间距,x[i]表示第i-1个加油站到第i 个加油站之间的距离。
x[0]即出发地到0号加油站的距离。
x[k-1]是第k-2个加油站到第k-1个加油站即终点的距离。
判断s加上x[i]后是否超出n,若超出则必定在i-1处加了油a[i-1]=true ,sum加1表示加油次数加一,且加油后里程从0开始计算,从i-1到达到i处里程为x[i]。
i++进入下一轮,即判断下一个加油站是否能到达。
3. 算法正确性证明通过几组实例证明合法的输入可以得到正确的输出。
实例见附录第2部分。
4. 算法复杂度分析O(n)5.参考文献[1] 王晓东编著,计算机算法设计与分析(第4版)。
北京:电子工业出版社,2012.26.附录(1)可执行代码如下:#include<iostream>using namespace std;int main(){int j,n,k,x[10],c=0,m=0;bool a[10];cout<<"请输入汽车加满油后可行驶的距离(km): ";cin>>n;cout<<"请输入旅途中所经过的加油站个数:";cin>>k;cout<<"请输入每两个相邻加油站之间的距离:"<<endl;for(int i=0;i<=k;i++)cin>>x[i];for(i=0;i<=k;i++)a[i]=false;for(j=0;j<=k;j++){m+=x[j];if(m+x[j+1]>=7){a[j+1]=true;m=0;}}cout<<"在第";for(int s=0;s<=k;s++)if(a[s]==true){c++;cout<<s<<" ";}cout<<"个加油站加油了。
1《算法设计与分析》期末大作业题目

综合题目:(1) 在8枚外观相同的硬币中,有一枚是假币,并且已知假币与真币的重量不同,但不知道假币与真币相比较轻还是较重。
可以通过一架天平来任意比较两组硬币,设计一个高效的算法来检测出这枚假币。
(2)动态规划法给定N个整数(可能有负数)组成的序列(a1,a2,···an),求该序列形如的字段和的最大值,当所有整数都为负数时,其最大字段和为0。
.(3) 贪心算法一辆汽车加满油后可以行驶N千米。
旅途中有若干个加油站。
若要使沿途的加油次数最少,设计一个有效的算法,指出应在那些加油站停靠加油。
并证明你的算法能产生一个最优解。
实验提示把两加油站的距离放在数组中,a[1..n]表示从起始位置开始跑,经过n个加油站,a[k]表示第k-1个加油站到第k个加油站的距离。
汽车在运行的过程中如果能跑到下一个站则不加油,否则要加油。
(4)回溯法下图是由14个“+”和14个“-”组成的符号三角形。
2个同号下面都是“+”,2个异号下面都是“-”。
+ + - + - + ++ - - - - +- + + + -- + + -- + -- -+在一般情况下,符号三角形的第一行有n个符号。
符号三角形问题要求对于给定的n,计算有多少个不同的符号三角形,使其所含的“+”和“-”的个数相同。
(5) 旅行商售货员问题的分支限界算法某售货员要到若干城市去推销商品,已知各城市之间的路程(或旅费)。
他要选定一条从驻地出发,经过每个城市一次,最后回到驻地的路线,使总的路程(或总旅费)最小。
(6) 使用回溯法编程,求解跳马问题实验内容问题描述:在N*N棋盘上有N2个格子,马在初始位置(X0,Y0),按照象棋中马走“日”的规则,使马走遍全部格子且每个格子仅经过一次。
编程输出马的走法。
给出算法描述。
编程实现,给出N=5,(X0,Y0)=(1,1)时的运行结果。
(7) 连珠(五子棋)是有两个人在一盘棋上进行对抗的竞技运动。
算法 加油问题

加油问题● 问题描述:一个旅行家想驾驶汽车从城市A到城市B(设出发时油箱是空的)。
给定两个城市之间的距离d1、汽车油箱的容量c、每升汽油能行驶的距离d2、沿途油站数n、油站i离出发点的距离d[i]以及该站每升汽油的价格p[i],i=1, 2,…,n。
设d[1]=0<d[2]< …<d[n]。
要花最少的油费从城市A到城市B,在每个加油站应加多少油,最少花费为多少?● 贪心选择策略:每到达一站i,找前面油价更便宜的最近一站j,在控制所加的油量至多只能行驶到站j的前提下,尽可能多加油。
目的:使得在每一段路(两相邻加油站之间)上所花的油费都尽可能少。
● 贪心算法:分析:(1) 设在第i站,汽车油箱剩余油量为r, 前面油价更便宜的最近一站为第j站,从第i站到第j站需油量m1, 则在第i站应加的油量x[i]分下列三种情况计算:1)r>=m1: 在第i站不加油,x[i]=0。
2)r<m1, c>=m1:在第i站加油使车刚好行驶至第j站,x[i]=m1-r。
3)c<m1:在第i站加满油,x[i]=c-r。
(2) 为了使汽车到终点时刚好油用完,在终点设一个虚拟油站n+1, 油价p[n+1]=0。
(3)注意问题可能无解,应判断。
算法CHEAPEST_TRA VEL输入:城市A、B间的距离d1,沿途油站数n,各油站距离出发点的距离数组d[1..n], (d[0]=0), 汽车油箱的容量c, 每升汽油能行驶的距离d2。
输出:从城市A到城市B所花费的最少油费min以及在各油站所加的油量x[1..n]。
若问题无解,则输出No Solution。
d[n+1]=d1; p[n+1]=0 //在终点设一个虚拟油站。
d3=c*d2 //d3为油箱加满油时可行驶的距离。
//检查问题是否有解。
i=1while i<=nif d[i+1]-d[i]>d3 then //无解输出“No Solution”; returnend ifi=i+1end whilemin=0r=0 //出发时油箱为空for i=1 to n//在第i站:j=i+1while p[j]>=p[i] //找站i前面油价更便宜的最近一站j。
算法设计与分析试卷答案

算法设计与分析1、(1) 证明:O(f)+O(g)=O(f+g)(7分)(2) 求下列函数的渐近表达式:(6分)① 3n 2+10n;② 21+1/n;2、对于下列各组函数f(n)和g(n),确定f(n)=O(g(n))或f(n)=Ω(g(n))或f(n)=θ(g(n)),并简述理由。
(15分)(1);5log )(;log )(2+==n n g n n f (2);)(;log )(2n n g n n f == (3);log )(;)(2n n g n n f == 3、试用分治法对数组A[n]实现快速排序。
(13分)4、试用动态规划算法实现最长公共子序列问题。
(15分)5、试用贪心算法求解汽车加油问题:已知一辆汽车加满油后可行驶n 公里,而旅途中有若干个加油站。
试设计一个有效算法,指出应在哪些加油站停靠加油,使加油次数最少。
(12分)6、试用动态规划算法实现下列问题:设A 和B 是两个字符串。
我们要用最少的字符操作,将字符串A 转换为字符串B ,这里所说的字符操作包括:(1)删除一个字符。
(2)插入一个字符。
(3)将一个字符改为另一个字符。
将字符串A 变换为字符串B 所用的最少字符操作数称为字符串A 到B 的编辑距离,记为d(A,B)。
试设计一个有效算法,对任给的两个字符串A 和B ,计算出它们的编辑距离d(A,B)。
(16分)7、试用回溯法解决下列整数变换问题:关于整数i 的变换f 和g 定义如下:⎣⎦2/)(;3)(i i g i i f ==。
对于给定的两个整数n 和m ,要求用最少的变换f 和g 变换次数将n 变为m 。
(16分)1、⑴证明:令F(n)=O(f),则存在自然数n 1、c 1,使得对任意的自然数n ≥n 1,有:F(n)≤c 1f(n)……………………………..(2分) 同理可令G(n)=O(g),则存在自然数n2、c 2,使得对任意的自然数n ≥n 2,有:G(n)≤c 2g(n)……………………………..(3分)令c 3=max{c 1,c 2},n 3=max{n 1,n 2},则对所有的n ≥n 3,有: F(n)≤c 1f(n)≤c 3f(n)G(n)≤c 2g(n)≤c 3g(n)……………………………..(5分) 故有:O(f)+O(g)=F(n)+G(n)≤c 3f(n)+c 3g(n)=c 3(f(n)+g(n))因此有:O(f)+O(g)=O(f+g)……………………………..(7分)⑵ 解:① 因为;01033)103(lim 222=+-+∞→n n n n n n 由渐近表达式的定义易知:3n 2是3n 2+10n 的渐近表达式。
算法分析大作业动态规划方法解乘法表问题和汽车加油行驶问题#精选.

算法分析⼤作业动态规划⽅法解乘法表问题和汽车加油⾏驶问题#精选.算法分析⼤作业动态规划⽅法解乘法表问题和汽车加油⾏驶问题⽬录1.动态规划解乘法表问题1.1问题描述------1.2算法设计思想------1.3设计⽅法------1.4源代码------1.5最终结果------2.动态规划解汽车加油⾏驶问题2.1问题描述------2.2算法设计思想------2.3设计⽅法------2.4源代码------2.5最终结果------3.总结1.动态规划解决乘法表问题1.1问题描述定义于字母表∑{a,b,c)上的乘法表如表所⽰:依此乘法表,对任⼀定义于∑上的字符串,适当加括号表达式后得到⼀个表达式。
例如,对于字符串x=bbbba,它的⼀个加括号表达式为(b(bb))(ba)。
依乘法表,该表达式的值为a。
试设计⼀个动态规划算法,对任⼀定义于∑上的字符串x=x1x2…xn,计算有多少种不同的加括号⽅式,使由x导出的加括号表达式的值为a。
1.2算法设计思想设常量a,b,c 分别为 1, 2 ,3 。
n 为字符串的长度。
设字符串的第 i 到第 j 位乘积为 a 的加括号法有result[i][j][a] 种,字符串的第 i 到第 j 位乘积为 b 的加括号法有result[i][j][b] 种,字符串的第 i 到第 j 位乘积为 c 的加括号法有 result[i][j][c] 种。
则原问题的解是:result[i][n][a] 。
设 k 为 i 到 j 中的某⼀个字符,则对于 k 从 i 到 j :result[i][j][a] += result[i][k][a] * result[k + 1][j][c] +result[i][k][b] * result[k + 1][j][c] + result[i][k][c] * result[k + 1][j][a];result[i][j][b] += result[i][k][a] * result[k + 1][j][a] +result[i][k][a] * result[k + 1][j][b] + result[i][k][b] * result[k + 1][j][b];result[i][j][c] += result[i][k][b] * result[k + 1][j][a] +result[i][k][c] * result[k + 1][j][b] + result[i][k][c] * result[k + 1][j][c];输⼊:输⼊⼀个以a,b,c组成的任意⼀个字符串。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法分析大作业动态规划方法解乘法表问题和汽车加油行驶问题目录1.动态规划解乘法表问题1.1问题描述------1.2算法设计思想------1.3设计方法------1.4源代码------1.5最终结果------2.动态规划解汽车加油行驶问题2.1问题描述------2.2算法设计思想------2.3设计方法------2.4源代码------2.5最终结果------3.总结1.动态规划解决乘法表问题1.1问题描述定义于字母表∑{a,b,c)上的乘法表如表所示:依此乘法表,对任一定义于∑上的字符串,适当加括号表达式后得到一个表达式。
例如,对于字符串x=bbbba,它的一个加括号表达式为(b(bb))(ba)。
依乘法表,该表达式的值为a。
试设计一个动态规划算法,对任一定义于∑上的字符串x=x1x2…xn,计算有多少种不同的加括号方式,使由x导出的加括号表达式的值为a。
1.2算法设计思想设常量a,b,c 分别为 1, 2 ,3 。
n 为字符串的长度。
设字符串的第 i 到第 j 位乘积为 a 的加括号法有result[i][j][a] 种,字符串的第 i 到第 j 位乘积为 b 的加括号法有result[i][j][b] 种,字符串的第 i 到第 j 位乘积为 c 的加括号法有 result[i][j][c] 种。
则原问题的解是:result[i][n][a] 。
设 k 为 i 到 j 中的某一个字符,则对于 k 从 i 到 j :result[i][j][a] += result[i][k][a] * result[k + 1][j][c] +result[i][k][b] * result[k + 1][j][c] + result[i][k][c] * result[k + 1][j][a];result[i][j][b] += result[i][k][a] * result[k + 1][j][a] +result[i][k][a] * result[k + 1][j][b] + result[i][k][b] * result[k + 1][j][b];result[i][j][c] += result[i][k][b] * result[k + 1][j][a] +result[i][k][c] * result[k + 1][j][b] + result[i][k][c] * result[k + 1][j][c];输入:输入一个以a,b,c组成的任意一个字符串。
输出:计算出的加括号方式数。
1.3设计方法乘法表问题直观理解就是通过加括号使得最终运算结果为a,该问题与矩阵连乘问题类似,矩阵连乘是每一次加括号选择运算量最小的,写成数学表达式有:而乘法表问题则是计算所有加括号运算结果为a的情况数,并不要求输出加括号方式。
那么可以从乘法的最小单元两个符号相乘的所有可能开始,接着在两个符号相乘的基础上计算三个符号相乘的所有可能。
直到计算N长度的符号1-N的所有可能。
可以定义一个三维数组a[n][n][3],n为输入字符串的长度,a[i][j][0]为从字符串中第i个元素到第j个元素的子串表达式值为a的加括号方式数,a[i][j][1]为从字符串中第i个元素到第j个元素的子串表达式值为b的加括号方式数,a[i][j][2]为从字符串中第i个元素到第j个元素的子串表达式值为c的加括号方式数。
由乘法表的定义则可知啊a[i][j][0]=(对k求和,k从i到j-1)a[i][k][0]*a[i][k+1][2]+a[i][k][1]*a[i][k+1][2]+a[i][k][2]*a[i][k+1][1];同理可得到a[i][j][1]和a[i][j][2]。
同时由上面的表达式可知,要计算a[i][j][],需先计算a[i][k][]和a[i][k +1][],这里k从i到j-1,故a[i][j][]可采取如下的计算次序1.4源代码#include "iostream"#include "algorithm"#include "fstream"using namespace std;/*f[i][j][0] 表示在ch[i]~ch[j]之间以某种方式加括号后,结果为a f[i][j][1] 表示在ch[i]~ch[j]之间以某种方式加括号后,结果为b f[i][j][2] 表示在ch[i]~ch[j]之间以某种方式加括号后,结果为ca = a*c || b*c || c*ab = a*a || a*b || b*bc = b*a || c*b || c*c */int f[50][50][3];char chars[3] = {'a', 'b', 'c'};int mul(int n, char ch[]){for(int i=0; i<n; i++)for(int k=0; k<3; k++)f[i][i][k] = (ch[i] == chars[k] ? 1: 0);/*a = a*c || b*c || c*ab = a*a || a*b || b*bc = b*a || c*b || c*c*/for(int r=1; r<n; r++) //规模for(i=0; i<n-r; i++) //区间左端点{int j = i + r; //区间右端点for(int k=i; k<j; k++) //断点{f[i][j][0] += f[i][k][0]*f[k+1][j][2] + f[i][k][1]*f[k+1][j][2] + f[i][k][2]*f[k+1][j][0];f[i][j][1] += f[i][k][0]*f[k+1][j][0] + f[i][k][0]*f[k+1][j][1] + f[i][k][1]*f[k+1][j][1];f[i][j][2] += f[i][k][1]*f[k+1][j][0] + f[i][k][2]*f[k+1][j][1] + f[i][k][2]*f[k+1][j][2];}}return f[0][n-1][0];}int main(){ifstream fin("mul.txt");cout << "输入字符串:";char ch[100];fin >> ch; cout << ch;int n = strlen(ch);cout << "\n结果为a的加括号方式为:" << mul(n, ch) << endl;fin.close();return 0;}1.5最终结果2.动态规划解决汽车加油行驶问题2.1问题描述给定一个N*N的方形网络,设其左上角为起点○,坐标为(1,1),X轴向右为正,Y轴向下为正,每个方格边长为1。
一辆汽车从起点○出发驶向右下角终点,其坐标为(M,N)。
在若干网格交叉点处,设置了油库,可供汽车在行驶途中,可供汽车在行驶途中加油。
汽车在行驶过程中应遵守如下规则:(1)汽车只能沿网格边行驶,装满油后能行驶K条网格边。
出发时汽车已装满油,在起点与终点处不设油库。
(2)当汽车行驶经过一条网格边时,若其X坐标或Y坐标减小,则应付费用B,否则免付费用。
(3)汽车在行驶过程中遇油库则应加满油并付加油费用A。
(4)在需要时可在网格点处增设油库,并付增设油库费用C(不含加油费A)。
(5)(1)~(4)中的各数N,K,A,B,C均为正整数。
2.2算法设计思想这个题目,应该说是刚开始的时候被他给吓到了,只是想着如何去把所有的条件构造起来,然后使用网络流的方式来解决问题!但是,如果真的是很冷静下来好好地思考这道题目,就会发现如果没有那些限制条件,就是一个求解最长路的题目,这样就可以直接使用SPFA来解决这个问题!关键就是在于这个每次最多只能走K个网格边,这样就是限制了活动的范围,使得有的边无法扩展!因此可以考虑使用这个分层思想的最短路问题!就是通过将每一个点进行拆分,这样,就是相当于一种分类讨论的方式!而分类讨论了之后,就知道哪些边是可以扩展的,哪些边是不能扩展的!关键点就是在于该如何选取变量来分层,这就是因情况而异了!像这道题目之中,就是通过油量的多少来扩展边的!分层思想,说穿了其实就是相当于这个动态规划之中的增加变量的方式来确定状态一样,他们的实质其实都是一样的!2.3设计方法采用的是动态规划的思想来解题,用备忘录的方法进行递归,递归的式子后面写出.不能直接以汽车行驶的费用为目标来进行动态规划,因为最优子结构性质得不到证明.所以必须把油量和费用一起考虑,作为动态规划的对象,此时就有了最优子结构性质.最优子结构性质的证明证明:假设路径M是从起点◎到终点▲的一条最小费用路径,P(x,y)是M 经过的一个点(非加油站),且油量和费用为(g,c),现假设有一条新路径Q从起点◎到点P(x,y),使得其在P(x,y)点的油量和费用为(g,c'),其中c'备忘录递归刚开始的时候为每个网格点P(x,y)建立一个记录,初始化时,为该记录存入一个特殊值W,表示汽车未行驶过.那么在汽车行驶过程中,对每个待求的汽车最小费用值COST,先查看其相应的记录项C,如果存储的是初始值W,那么表示这个点P(x,y)是第一次遇到,此时计算出该点的最小费用值,并保存在其相应的记录项中,以备以后查看.若记录项C中存储的不是初始值W,那么表示该问题已经求解过了,其相应的记录项中存储的就是该点的最小费用值COST,此时要取出记录项C的值跟最新的计算出的COST进行比较,取其最小的那个数存入到C中.依此建立记录项C的值,当程序递归完成时,我们也得到了汽车行驶到(n,n)的最小费用值COST.2.4源代码#include "iostream"#include "algorithm"#include "fstream"using namespace std;#define INF 10000/*f[i][j][0]表示汽车从网格点(1,1)行驶至网格点(i,j)所需的最少费用f[i][j][1]表示汽车行驶至网格点(i,j)还能行驶的网格边数s[i][0]表示x轴方向s[i][1]表示y轴方向s[i][2]表示行驶费用f[i][j][0] = min{f[ i+s[k][0] ][ [j+s[k][1] ][0] + s[k][2]}f[i][j][1] = f[ i+s[k][0] ][ [j+s[k][1] ][1] - 1;f[1][1][0] = 0f[1][1][1] = Kf[i][j][0] = f[i][j][0] + A , f[i][j][1] = K 如果(i, j)是油库f[i][j][0] = f[i][j][0] + C + A, f[i][j][1] = K (i, j)不是油库,且f[i][j][1] = 0*/int N; //方形网络规模int A; //汽车在行驶过程中遇到油库应加满油并付加油费Aint C; //在需要时可在网格点处增设油库,并付增设油库费用C(不含加油费A)int B; //当汽车行驶经过一条网格边时,如果其x坐标或y坐标减少,应付费用Bint K; //装满油后,还能行驶K条边int f[50][50][2];int s[4][3] = {{-1,0,0},{0,-1,0},{1,0,B},{0,1,B}};int a[50][50]; //方形网络int dyna(){int i, j, k;for (i=1;i<=N;i++){for (j=1;j<=N;j++){f[i][j][0]=INF;f[i][j][1]=K;}}f[1][1][0] = 0;f[1][1][1] = K;int count = 1;int tx, ty;while(count){count = 0;for(i=1; i<=N; i++){for(int j=1; j<=N; j++){if(i==1 && j==1)continue;int minStep = INF;int minDstep;int step, dstep;for(k=0; k<4; k++) //可走的四个方向{tx = i + s[k][0];ty = j + s[k][1];if(tx<1 || ty<1 || tx>N || ty>N) //如果出界continue;step = f[tx][ty][0] + s[k][2];dstep = f[tx][ty][1] - 1;if(a[i][j] == 1) //如果是油库{step += A;dstep = K;}if(a[i][j]==0 && dstep == 0 && (i!=N||j!=N)) //如果不是油库,且油已经用完{step += A + C;dstep = K;}if(step < minStep) //可以走{minStep = step;minDstep = dstep;}}if(f[i][j][0] > minStep) //如果有更优解{count++;f[i][j][0] = minStep;f[i][j][1] = minDstep;}}}}return f[N][N][0];}int main(){ifstream fin("car.txt");cout << "输入方格规模:";fin >> N; cout << N;cout << "\n输入装满油后能行驶的网格边数:";fin >> K; cout << K;cout << "\n输入加油费:";fin >> A; cout << A;cout << "\n输入坐标减少时应付的费用:";fin >> B; cout << B; s[2][2] = s[3][2] = B;cout << "\n输入增设油库费用:";fin >> C; cout << C;cout << "\n输入方形网络:\n";for(int i=1; i<=N; i++){for(int j=1; j<=N; j++){fin >> a[i][j];cout << a[i][j] << " ";}cout << endl;}cout << "最优行驶路线所需的费用为:" << dyna() << endl; fin.close();return 0;}2.5最终结果3.总结动态规划(Dynamic Programming, DP)思想启发于分治算法的思想,也是将复杂问题化解若干子问题,先求解小问题,再根据小问题的解得到原问题的解。