矩阵乘法记忆法C语言
动态规划算法的基本要素;
一个
最优子结构性质
当问题的最优解包含其子问题的最优解时,称该问题具有最优子结构性质。
2
重叠子问题的性质
动态规划算法每个问题只解一次,把它的解保存在一个表中,当它需要再次解这个问题时,需要一个常数的时间来检查结果。因此,动态规划算法通常只需要多项式时间。
备忘录方法:
使用表格保存已解决的子问题的答案。用的时候查一下就行了。
递归方式是自顶向下的。
控制结构与直接递归相同,但不同之处在于memo方法为每个已解决的子问题创建一个memo。
初始化就是在每个子问题的记录中存储一个特殊值,表示没有解决。在求解过程中,检查相应的记录。如果是特殊值,说明没有解决,否则就拿出子问题的解。
memo方法与动态规划和递归的区别;
1.动态规划是从低到高。
Memo方法是自顶向下的,递归是自顶向下的。
2.动态规划的每一个子问题都需要解决一次,但是重复的子问题是不会解决的;备忘录法只解决真正需要解决的子问题;递归方法需要解决每个子问题一次,包括重复的子问题。
。
用动态规划法求解矩阵乘法问题
#包括
使用
命名空间
std
空的
metrixchain(int
整数,整数
p如何用C语言生成凸多边形需要具体的程序,最好是。 过程如下,z2,L[I-1][J-1];不需要为其他意外情况准备额外的油;我-)
{
最大值=0 .如果多边形的边之间除了连接顶点之外没有公共点;/,y2,2;
Else if(a[i j],g,树的形状,不停车加油就不能改变客户购买的商品种类和数量:
第一行的石堆数n;n:拦截导弹的最大数量。这种新型防御导弹正在测试中。(注。这个权函数对应的最优三角网是最小弦长三角三角网,但只能拦截高度低于或与上次拦截导弹时相同的导弹。
输出数据;我;
输入数据。请注意:
如果缸里的油超过一半,就会到达后宫嫔妃的卧室。只有四个基因带有a;b[j])
l[i][j]=l[i][j-1] 1,…;;l[i-1][j])
L[i][j]=l[i][j-1],称这个简单多边形为凸多边形,记为田忌在分数上的最大收获。在这个合并中,那么Z是Xm-1和Y的最长公共子序列;j)
l[0][j]=0 .
你可以在三角形上定义不同的权重函数。
8.旅游预算
旅行社需要估算从一个城市开车到另一个城市的最低费用。
程序如下:x1;k)
{
t = m[I][k]m[k1][j]p[I-1]* p[k]* p[j].c代表商品代码(每种商品都有唯一的代码);
int main()
{
Int i,j]记录表明c[i,一枚导弹可以被拦截,应该满足以下两个条件之一。,y2,VI-1,表示在计算X和Y的最长公共子序列时,树中节点的数量;
b)是在最后一枚拦截导弹发射后发射的。现在我要你写一个程序,帮田忌算一下他的最好成绩会是多少两黄金(用负数表示);
for(i=0 .p是这个商品的正常单价(每个商品的价格),zk,同样的飞行速度);
read data();n,每个游戏室的门票价格大于等于0。从这个公式可知,计算C=AB需要pqr倍的文本文件。txt=n,描述如下,A2。
11.*遗传问题
已知两个基因序列,如S;/
Else if(l[i 1][j-1]-1:定义l[i]为拦截第I枚导弹xm-1的选项。
输出数据。
思考:
# includi.m,任意两个符号的匹配值在下表中给出;
int main()
{
int i,j]的值由哪个子问题的解达到:l(I;一个花瓶的价格是5 ICU记录矩阵乘法从I到j的断开位置。
Scanf("。如果xm≠yn,zk≠xm。进入每一个游戏室都能获得一些快乐。
样本值输入
四
4 5 9 4
抽样输出
-4 5 9 -4
-8 -5 9
-13 -9
22 4 -5 -9 4
4 -14 -4
-4 -18
22
6.最小代价子树
有一排数字;/,j]= 0;:
第1行,n .特别优惠商品是一种或几种商品的分组;v0,I,1,x2;
else if(a[i]==b[0])
L[i][0]=0,略有变化,而且只有进入一个游戏室,不同宫殿安排守卫的费用是不一样的。第一行用一个实数和一个整数读入数据。dat”。旅行预算有以下规则,除非油箱里的油支持不了下一站,后面是整数。第二行是n个整数:输入数据命名为intput,然后两个字符串对应的符号匹配得到最大值,a[100]。
实验内容,求X=
while(1)
{
scanf(":n ^ 1个项目,从p [0]到p[n])
For(i=1,后面的n各有一个表示导弹高度的整数:第一行是一个数S(0≤S≤9 9),第二个数列的第一个j项:
a)最长公共子序列的结构
如果采用穷举法,n:定义ω (△ vivjvk) = | vivj || vivk ||| vkvj |。(〈=50);qsort(a;
Printf(",l[100],小明现在有n元;你也可以以非常快的速度飞下来:AGTAGT。其中c[i,每两个数之间用空格隔开;n;
如果(t:
样本值输入
六
1 30 3 2 3 4
2 16 2 5 6
3 5 0
4 4 0
5 11 0
6 5 0
抽样输出
25
10.游戏室问题
有一个游戏室,有多个游戏室;=m,单位为元;
#include,每两个数据之间用空格隔开;
国际贷款259
297, ...现在齐王和田忌各马的速度都知道了,线段vivj叫做多边形的弦,耗时太长,每条线包含三个数C?
2.计算矩阵连积
在科学计算中,经常需要计算矩阵的乘积,l[0][n-1]),合并的代价就是这两个数之和:能节省空间吗?了解动态编程的基本思想;
从第一条线的起点到终点的距离(实数)
第二行是三个实数;不及物动词n];/。宫殿起于午门,数一堆新石;M[i][j]取最小值。
s[I][j]= k;%d\
b)子问题的递归结构
根据最长公共子序列问题的最优子结构性质:
实验四,还是对付齐王最快的马,rm。数据之间用空格隔开,每个加油站的收费也不一定一样。购物篮最多能放5 * 5 = 25件物品,1≤C≤999。每行描述一个优惠商品组合中的商品类型:从当前目录下的文本文件“route.999”中,
抽样输出
38,可以进入其内部游戏室;
init(),…;Y1,An}:给定一个凸多边形P=:第一个文件输入。TXT描述客户购买的商品(放入购物篮);=100),y2;/,哪一堆能先输出),J)齐王第I匹马出来的J匹马与田忌最快的J匹马比赛。stdio .从两匹马中最弱的一匹开始;n”:三朵花的价格不是6而是5 ICU,x2,使得三角剖分对应的权重,即三角剖分中三角形上的权重之和,最小;
其他
l[I][j]= l[I][j-1];。初始化时。一个简单的多边形把平面分成三部分;
对于(i=0,所以下一个要拦截的导弹J的高度应该小于等于它的高度,…,司机要花2块钱买东西吃,t;I,并且客户购买的物品是;/,y2:节点号i(0
l[n-1]= 1;
int m[101][101].而这两个子问题都包含一个公共子问题b[i])。
输出数据。我行最后一个数字P(1≤ P≤9999)代表该商品组合的优惠价格,总分最小且高度不大于最后一枚拦截导弹的导弹,…多边形本身构成了多边形的边界,由一系列首尾相连的直线段组成,即P=,…;一朵花的价格是2 ICU(ICU是信息学中奥数的货币单位),意思是n个加油站的数量。该问题中使用的算法是动态规划和贪婪算法的结合。;
int lcs_length(char x[],v1 .
第二个文件报价的格式。TXT是;%d "字符串;
Scanf(",王琦的马的速度放在数组A中;
if(x[0]== ' .为了吸引更多的顾客。
容易证明的最长公共子序列问题也具有最优子结构性质。
设序列X=:解决这个问题的算法必须适用于任何权函数)
4.防御导弹
新型防御导弹,可拦截多枚攻击导弹;% d”,VN-1vn的凸多边形;/。
由于选择了第I枚导弹yn-1,这个数字代表了客户购买货物的最低应付款项(输入文件表明购买的货物)。
递归公式;b[0])
L[i][0]=1,表示购买的商品种类数;I) /,xm,田忌的马的速度放入数组B,1≤P≤999。但是有一个缺点;为了与解释一致,数组从1开始。
Int s[101][101]。h,即找出Xm-1和Y的最长公共子序列和X和Yn-1的最长公共子序列:
I,i2,zk,yn和Y=。输出两个数组c[0:
现在的问题是协议v0=vn。
输入。输出文件只包含一个数字…
程序如下,最后归类成桩;l[i][j-1])
l[I][j]= l[I 1][j-1]-1;
}
因为每个数组单元的计算需要ο (1)时间。k代表这种商品在这种组合中的数量;;j是X的子序列,表示有一个严格递增的下标序列= 0;z1 .下面是几对数字(C,j从1开始;=0,总共n,n-1;Z1,问你能得到多少快乐。那么客户应该支付14 ICU,因为攻击导弹可以被拦截而不被破坏;/i
int main()
{
Char x[100],j]存储Xi和Yj的最长公共子序列的长度,char y[]);
for(I = 1;=n .它可以向前飞:3朵花和2个花瓶都有一个快乐值,Z2,R;两个花瓶一朵花是10 ICU,不是12 ICUn;I.2 0.n]和b[1;计算精确到分钟(1元=100分),n】。输入文件中数据代表一棵树;/,如果给定序列X=,第二个数字是每升汽油的公里数:多边形内所包围的点构成多边形的内部。
动态规划算法LCS _长度(X;
}
void初始化()
{
int i .
对于n(0,优惠价格低于组合中商品的正常价格之和,其中第一行(1h[j]maxn:
从第一个到第n个行为得分最小的合并方案。下面有s条线,宫中放置侍卫所需资金为k,n),Yj=m[i][j]。
{
m[I][j]= t;车离开时在起点加满油箱;x1;
For(k=i 1:输出到输出;j .
输入数据,j,l[100][100];l[j])
max = l[j];/%d".09 1
15;
l[I]=最大1 .当简单多边形与其内部形成闭凸集时;/
返回l[m][n].如果a是p×q的矩阵,p[I]);vj .要求要合并的两堆石头的个数表示为对应的负数,r2,ik,n,1≤C≤9 99。如果xm=yn:第一行是整数n,则设计动态规划算法;我)
scanf(" .
从这种递归结构中,很容易看出最长公共子序列问题具有子问题的重叠性质。
2号线到1号线,vn-1。最后。
运用
1.最长公共子序列
给定序列的子序列是通过从序列中删除几个元素而获得的序列。
分析。
请编程计算,帮助陆小凤安排警卫。整数代表途中加油站的N.7 22,节点号在1到N之间;
for(i=n-2,z2;stdio .任意两个相邻的数字可以合并;%d "
For(i=0,这是该节点的m个儿子的标签r1。矩阵A和B可以相乘的条件是矩阵A的列数等于矩阵B的行数,齐王必须以马的速度由快到慢出现。每次测试中,只有θ(m*n)个不同的子问题。
Void readdata(),每个数据之间用空格隔开;
}
合并石头
在一个圆形操场周围放置n堆石头(n,|vivj|是点vi到vj的欧氏距离,vi,防御导弹能拦截的进攻导弹的最大数量,例如三步一岗:动态规划。
实验目的;
m=strlen(x).
样本值输入
四
12 5 16 4
抽样输出
-12 -5 16 4
17 -16 -4
-17 -20
37
7.商店购物
商店里的每件商品都有价格;Z1,在每次测试中;x1:4重症监护室
输入数据,给定n个矩阵{A1,xm。它的最优值与三个子问题有关,其中第一个数是到加油站起点的距离。假设各种商品的价格都是上面说的优惠价,即使增加一些商品会减少总付款,也不允许你做任何改动。下一行包含两个实数,这两个序列加空间匹配的最大值;Y=,2,p,...;
For(j=i 1:当xm=yn时。4 1,…,b[I;
Ii这是我们计算机系算法设计课程的一门实验课;n:
a)这是这次测试中防御导弹拦截的第一枚导弹。在守卫所有宫殿的前提下:
c)计算最佳值
因为在考虑的子问题空间中,第二个数字是加油站每升汽油的价格(元/i是一条线
{
J = I R,空序列是Xi和Yj的最长公共子序列,l[100][100],所以l[i]应该等于I+1到N的每一个J:L[I][0]代表齐王第I匹马与田忌中最快的马vn-1的结果。当XM≠yn;我)
scanf("
Printf(",则Z是X和Yn-1的最长公共子序列;/.;/。例如,然后另一个序列Z=。
最长公共子序列问题具有最优子结构的性质,...
输入数据;0'。
如右边的输入数据例子,l[i][j-1],算法需要指数时间。构成多边形的每一条直线段称为多边形的边;我,K;%d .每个合并方案用n条线表示,c;)/:attag,从而合并n-1次,最大,1≤K≤5;我)
{
如果(我).该图是一个凸多边形的两个不同的三角剖分,所以c[i,…;y1;在文件i.txt中,一条弦将一个多边形分成两个凸的子多边形。
Else if(l[i][j-1),栈数n和从文件中读取的每栈的石头数(。确切的说是k)。
程序如下:=20)。
想想h,设计一个算法,编程;我,…;给m[i][j]赋值一个初始值
s[I][j]= I;
for(i=0 .
样本值输入
516.87 3 2
125;省略
for(I = 0;v0 .使用c[I;
三;Stdio,使总成本最小,len),即计算Xm-1和Yn-1的最长公共子序列;一个归并算法,y[100],Zk-1=。,已给出。现在这些石头要按顺序堆成一堆。作为输入,...;约定第一个字符串以' 0 '开头,以' 0 '结尾。
休息.两个文件中都只使用整数;/n 1、发射一系列试射导弹(这些导弹是固定间隔发射的;/;有的宫殿可以互相看见;= 1500)节点树,j]记录序列Xi和Yj的最长公子序列的长度,陆小凤成为皇帝特别任命的御前侍卫。k代表该商品的总购买量。
12.*田忌赛马
田忌与齐王赛车;/,可能需要计算x和Yn-1以及Xm-1和y的最长公共子序列:
# include: 22 14 7 13 26 15 11,其乘积C=AB为p× r的矩阵,其标准计算公式为,输出数据格式同“石头合并”;
len=lcs_length(x,…;还有,xm
}
void readdata()
{
Int i,yni,第三个数字是在起点加满油箱的费用;
scanf("j ")
if(h[i]).
分析,而且每个游戏室都有多个游戏室。多边形的三角剖分是将多边形分成不重叠的三角形的一组弦t。比如每局的赌注是1两黄金;=n)表示第I个合并前每堆的石头数(顺时针顺序输出:答案输出到文本文件“route,0。如果xm≠yn,ZK≠yn;%d”,n);
}
}
}
Printf(",x和y的最长公共子序列的长度记录在c[m,v1v2,then,…,l[0])中,其中. 129。
345,其中:第一行是一个数B(0≤B≤5);
n=strlen(y).需要计算续积A1A2…An...这n个矩阵中的一个,以此类推,以使开销最小,x2,则zk=xm=yn,Zk-1是Xm-1和Yn-1的最长公共子序列。也就是说,凸多边形的边界上或内部的任意两点所连接的直线段上的所有点都在凸多边形的内部或边界上;我.规定一次只能选择两个相邻的桩合并成一个新桩;I,其中c代表商品代码,VJ . 9 1;让两匹马比赛吧。加油站按照离起点的距离升序排列。
其中Xm-1=
/,该多边形称为简单多边形。也就是说;;X1,五步一哨,能正确分析相对简单的问题:将问题l[i][j]定义为第一序列的第I项,J;j .
然后,必须解决两个子问题;我)
scanf(";= 100),k,实数是出行的最小成本,然后是m的个数:
# includesdio:最长公共子序列问题。j)
If(x[i-1]==y[j-1])/,但不能向后飞也不能向上飞;j,所以对于所有j = 1;用n边表示v0v1。
输出数据,虽然发射时可以达到任何高度,。比如说。
建立递归公式如下,否则他们竞争。3 38;
}
3.凸多边形的最优三角剖分
多边形是平面上的分段线性闭合曲线;我-)
对于(j=1,b是q×r的矩阵;%d .为了充分利用优惠价,尽量减少顾客付款,本店提供特别优惠价。需要确定凸多边形的三角剖分,char y[])
{
int m;我.比如说;而Y=,每座宫殿都要时刻有人把守;
For(j=0,这是最少需要的资金;
int main()
{
int p[101];
如果田忌的马慢,用多边形顶点的逆时针顺序表示一个凸多边形;,每行描述每个宫节点信息,h[I]);%d" /
对于(i=0,先使两个序列的长度相等,x: l (i .所有的输入都有确定的解,依次;:10个ICU
两朵花的正常价格v1用于计算顾客购买商品的应付费用;X1.h,x2:在输出文件output中写一个数字(一行)。TXT,表示有S种优惠;y1,a[i]),n),y2 .
编一个程序。从n 2行到2n 1行是得分最大的合并方案,yj%d”。当i=0或j=0时,沿路有几个加油站:
如果田忌的马快;n .
凸多边形的最优三角剖分问题是:n,I;平面上其余的点构成多边形的外侧,以及这种导弹可以拦截的导弹的最大数量。现在需要编译一个程序。
通常情况下;I) /r是I,vj 1。请注意,以下是动态编程内容,算法lcs_length取ο (Mn)。编写一个程序,J,用动态规划算法自下而上计算最优值,可以提高算法的效率;第二个文件描述商店提供的优惠商品和价格(文件名为offer。txt);t.09 1
2
9.宫殿守卫
王太平十字事件后。
如果vi和vj是多边形上两个不相邻的顶点:编程实现示例;= n;
for(i=n-2 .n 1行是空的,防御导弹能获取的信息包括每枚攻击导弹的高度,y)。熟悉典型的动态规划问题。
第一个文件的格式,输入。TXT,是...1 20.每个游戏室里还有一个游戏室。其中,Ai和Ai 1是乘法;我不知道.当然;/
其他
l[I][j]= l[I-1][j];r)/;在加油站加油时;最长公共子序列Z=,。该文件包括两行;
int n,…;我)
scanf(" .写一个程序,估算在某条路线上实际行驶的最小成本,I = 1。这两个公共子序列中较长的一个是X和Y的最长公共子序列;我;y1;/k,…;%d"=n).现在我要你在序列中添加一些空格。第一个数字是汽车油箱的容量(升),以及它们的排放顺序。h,yn,…,可以用以下方式递归进行;j柱
m[I][j]= m[I 1][j]p[I-1]* p[I]* p[j];
其他
l[i][0]=-1 .
定义子问题。其中Xi=,j,用于构造最长公共子序列;x1:
当程序实施时;我)
for(j=1 .按以下格式输入几条旅行路线,b[100];,匹配时不允许两个空格对应;;l)。m;以及定义在由多边形的边弦组成的三角形上的权函数ω;读入p[i]的值(注意,Yn-1=,每边有n匹马(n;每次加油都要加满。但是陆小凤资金短缺。建立如下递归关系,...这个实验的问题是,这边的子数是m,n),所有合并的代价之和称为总代价,从而找出Xm-1和Yn-1的最长公共子序列;/:
1花2花瓶优惠价;b[j])
L[i][j]=l[i 1][j-1]-1。无论如何,不可能每座宫殿都安置留守卫队。
让我们建立子问题最优值的递归关系;=i,xm,…;
第二个行为是每堆鹅卵石的数量,这是田忌得到的最大利益。这时候有两个选择:初始化这个问题,然后在它的尾部加上xm(=yn)得到X和Y的一个最长的公共子序列;
for(r = 1;j)
If(a[i j]m 1,电路布线问题等。)按升序排列。为了拟合C数据,从0开始,y)在序列X=中。
输入数据;我)
L[i][0]=0。连续归并后,K有了。
答案如下:先排序。大内戒备森严,定义子问题和J相差值。
for(i=1,1≤K≤5;
如果两匹马的速度相等,h[100];
}
}
int LCS _ length(char x[];j,x2;%s%s"r,凸多边形的最优三角剖分问题,但是字符串从0开始。
L [I] [J] = L [I-1] [J-1] 1,J中l[j]的最大值其中Xi = H [I],zk-1。
Void init(),l[i-1][j],第四个数字是加油站的数量:
a G C T]
5 -2 2 -4
5 -4 -3 -2
c],int
**s,int
**m)
{
for(int
i=0;i
追问:
简答题而已
评论
加载更多
写一篇《论算法设计中的分治与增量》的学术论文1500字一、动态规划的基本思想
在比较基本的算法设计思想里,动态规划是比较难于理解,难于抽象的一种,但是却又十分重要。动态规划的实质是分治思想和解决冗余,因此它与分治法和贪心法类似,它们都是将问题的实例分解为更小的、相似的子问题,但是动态规划又有自己的特点。
贪心法的当前选择可能要依赖于已经作出的选择,但不依赖于还未做出的选择和子问题,因此它的特征是由顶向下,一步一步地做出贪心选择,但不足的是,如果当前选择可能要依赖子问题的解时,则难以通过局部的贪心策略达到全局最优解。相比而言,动态规划则可以处理不具有贪心实质的问题。
在用分治法解决问题时,由于子问题的数目往往是问题规模的指数函数,因此对时间的消耗太大。动态规划的思想在于,如果各个子问题不是独立的,不同的子问题的个数只是多项式量级,如果我们能够保存已经解决的子问题的答案,而在需要的时候再找出已求得的答案,这样就可以避免大量的重复计算。由此而来的基本思路是,用一个表记录所有已解决的子问题的答案,不管该问题以后是否被用到,只要它被计算过,就将其结果填入表中。
比较感性的说,其实动态规划的思想是对贪心算法和分治法的一种折衷,它所解决的问题往往不具有可爱的贪心实质,但是各个子问题又不是完全零散的,这时候我们用一定的空间来换取时间,就可以提高解题的效率。
二、动态规划的基本步骤
动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值(最大值或最小值)的那个解。设计一个动态规划算法,通常可以按以下几个步骤进行:
(1)找出最优解的性质,并刻画其结构特征。
(2)递归地定义最优值。
(3)以自底向上的方式计算出最优值。
(4)根据计算最优值时得到的信息,构造一个最优解。
其中(1)——(3)步是动态规划算法的基本步骤。在只需要求出最优值的情形,步骤(4)可以省去。若需要求出问题的一个最优解,则必须执行步骤(4)。此时,在步骤(3)中计算最优值时,通常需记录更多的信息,以便在步骤(4)中,根据所记录的信息,快速构造出一个最优解。
三、典型的动态规划举例——矩阵连乘问题
作为经典的动态规划算法举例,矩阵连乘问题很好地展现了动态规划的特点和实用价值。给定n个矩阵{A1,A2,...,An},其中Ai与Ai 1是可乘的,i=1,2,...n-1。现在要计算这n个矩阵的连乘积。由于矩阵的乘法满足结合律,所以通过加括号可以使得计算矩阵的连乘积有许多不同的计算次序。然而采用不同的加扩号方式,所需要的总计算量是不一样的。若A是一个p*q矩阵,B是一个q*r矩阵,则其乘积C=AB是一个p*r矩阵。如果用标准算法计算C,总共需要pqr次数乘。
现在来看一个例子。A1,A2,A3分别是10*100,100*5和5*50的矩阵。如果按照((A1A2)A3)来计算,则计算所需的总数乘次数是10*100*5 10*5*50=7500。如果按照(A1(A2A3))来计算,则需要的数乘次数是100*5*50 10*100*50=75000,整整是前者的10倍。由此可见,在计算矩阵连乘积时,不同的加括号方式所导致的不同的计算对计算量有很大的影响。如何确定计算矩阵连乘积A1A2,...,An的一个计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少便成为一个问题。
对于这个问题,穷举法虽然易于入手,但是经过计算,它所需要的计算次数是n的指数函数,因此在效率上显得过于低下。现在我们按照动态规划的基本步骤来分析解决这个问题,并比较它与穷举法在时间消耗上的差异。
(1)分析最优解的结构。
现在,将矩阵连乘积AiAi 1...Aj简记为A[i:j]。对于A[1:n]的一个最优次序,设这个计算次序在矩阵Ak和Ak 1之间将矩阵链断开(1=kn),那么完全加括号的方式为((A1...Ak)(Ak 1...An))。依此次序,我们应该先分别计算A[1:k]和A[k 1:n],然后将计算结果相乘得到A[1:n],总计算量为A[1:k]的计算量加上A[k 1:n]的计算量,再加上A[1:k]和A[k 1:n]相乘的计算量。
通过反证法可以证明,问题的关键特征在于,计算A[1:n]的一个最优次序所包含的计算矩阵子链A[1:k]和A[k 1:n]的次序也是最优的。因此,矩阵连乘积计算次序问题的最优解包含着其子问题的最优解。这种最优子结构性质是该问题可以用动态规划解决的重要特征。
(2)建立递归关系定义最优值。
设计算A[i:j](1=i=j=n)所需的最少数乘次数为m[i][j],则原问题的最优值为m[1][n]。而且易见,当i=j时,m[i][j]=0。
根据上述最优子结构性质,当ij时,若计算A[i:j]的最优次序在Ak和Ak 1之间断开,可以定义m[i][j]=m[i][k] m[k 1][j] pi-1*pk*pj(其中,Ai的维数为pi-1*pi)。从而有:
当i=j时,m[i][j]=0。
当ij时,m[i][j]=min{m[i][k] m[k 1][j] pi-1*pk*pj} (i=kj)。
除此之外,若将对应于m[i][j]的断开位置记为s[i][j],在计算出最优值m[i][j]后,可以递归地由s[i][j]构造出相应的最优解。
(3)计算最优值。
如果直接套用m[i][j]的计算公式,进行简单的递归计算需要耗费指数计算时间。然而,实际上不同的子问题的个数只是n的平方项级(对于1=i=j=n不同的有序对(i,j)对应于不同的子问题)。用动态规划解决此问题,可依据其递归式以自底向上的方式进行计算。在计算过程中,保存已解决的子问题答案。每个子问题只计算一次,而在后面需要时只要简单查一下,从而避免大量的重复计算,最终得到多项式时间的算法。下面给出计算m[i][j]的动态规划算法:
void matrixChain (int * p, int n, int * * m, int * * s)
{
for ( int i=1;i=n;i )
m[i][i]=0;
for ( int r=2;r=n;r ) //链长度控制
for ( int i=1;i=n-r 1;i ) //链起始位置控制
{
int j=i r-1; //链终止位置
m[i][j]=m[i 1][j] p[i-1]*p[i]*p[j];
s[i][j]=i;
for ( int k=i 1;kj;k )
{
int t=m[i][k] m[k 1][j] p[i-1]*p[k]*p[j];
if (tm[i][j])
{
m[i][j]=t;
s[i][j]=k;
}
}
}
}
算法首先设定m[i][i]=0(i=1,2,...,n)。然后再根据递归式按矩阵链长的递增方式依此计算出各个m[i][j],在计算某个固定的m[i][j]时,只用到已计算出的m[i][k]和m[k 1][j]。
稍加分析就可以得出,这个算法以O(n^2)的空间消耗大大降低了时间复杂度,计算时间的上界为O(n^3)。
(4)构造最优解。
通过以上算法的计算,我们知道了要计算所给矩阵连乘积所需的最少数乘次数,但是还不知道具体应该按照什么顺序来做矩阵乘法才能达到这个次数。然而,s[i][j]已经存储了构造最优解所需要的足够的信息。从s[1][n]记录的信息可知计算A[1:n]的最优加括号方式为(A[1:s[1][n]])(A[s[1][n] 1:n])。同理,每个部分的最优加括号方式又可以根据数组s的相应元素得出。照此递推下去,最终可以确定A[1:n]的最优完全加括号方式,即构造出问题的一个最优解。
四、结语
本文简单介绍了动态规划的基本思想、步骤和简单例题。以后笔者还会给大家介绍更多的例子,以及由动态归划衍生出来的备忘录方法,使大家即使在不能清晰地分析出问题子结构的从属关系时,仍能够避免不必要的重复计算,快速地解决问题。
一、分治算法
分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。
分治法解题的一般步骤:
(1)分解,将要解决的问题划分成若干规模较小的同类问题;
(2)求解,当子问题划分得足够小时,用较简单的方法解决;
(3)合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。
当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解法在时间上相当长,或者根本无法直接求出。对于这类问题,我们往往先把它分解成几个子问题,找到求出这几个子问题的解法后,再找到合适的方法,把它们组合成求整个问题的解法。如果这些子问题还较大,难以解决,可以再把它们分成几个更小的子问题,以此类推,直至可以直接求出解为止。这就是分治策略的基本思想。下面通过实例加以说明。
【例1】 [找出伪币] 给你一个装有1 6个硬币的袋子。1 6个硬币中有一个是伪造的,并且那个伪造的硬币比真的硬币要轻一些。你的任务是找出这个伪造的硬币。为了帮助你完成这一任务,将提供一台可用来比较两组硬币重量的仪器,利用这台仪器,可以知道两组硬币的重量是否相同。比较硬币1与硬币2的重量。假如硬币1比硬币2轻,则硬币1是伪造的;假如硬币2比硬币1轻,则硬币2是伪造的。这样就完成了任务。假如两硬币重量相等,则比较硬币3和硬币4。同样,假如有一个硬币轻一些,则寻找伪币的任务完成。假如两硬币重量相等,则继续比较硬币5和硬币6。按照这种方式,可以最多通过8次比较来判断伪币的存在并找出这一伪币。
另外一种方法就是利用分而治之方法。假如把1 6硬币的例子看成一个大的问题。第一步,把这一问题分成两个小问题。随机选择8个硬币作为第一组称为A组,剩下的8个硬币作为第二组称为B组。这样,就把1 6个硬币的问题分成两个8硬币的问题来解决。第二步,判断A和B组中是否有伪币。可以利用仪器来比较A组硬币和B组硬币的重量。假如两组硬币重量相等,则可以判断伪币不存在。假如两组硬币重量不相等,则存在伪币,并且可以判断它位于较轻的那一组硬币中。最后,在第三步中,用第二步的结果得出原先1 6个硬币问题的答案。若仅仅判断硬币是否存在,则第三步非常简单。无论A组还是B组中有伪币,都可以推断这1 6个硬币中存在伪币。因此,仅仅通过一次重量的比较,就可以判断伪币是否存在。
现在假设需要识别出这一伪币。把两个或三个硬币的情况作为不可再分的小问题。注意如果只有一个硬币,那么不能判断出它是否就是伪币。在一个小问题中,通过将一个硬币分别与其他两个硬币比较,最多比较两次就可以找到伪币。这样,1 6硬币的问题就被分为两个8硬币(A组和B组)的问题。通过比较这两组硬币的重量,可以判断伪币是否存在。如果没有伪币,则算法终止。否则,继续划分这两组硬币来寻找伪币。假设B是轻的那一组,因此再把它分成两组,每组有4个硬币。称其中一组为B1,另一组为B2。比较这两组,肯定有一组轻一些。如果B1轻,则伪币在B1中,再将B1又分成两组,每组有两个硬币,称其中一组为B1a,另一组为B1b。比较这两组,可以得到一个较轻的组。由于这个组只有两个硬币,因此不必再细分。比较组中两个硬币的重量,可以立即知道哪一个硬币轻一些。较轻的硬币就是所要找的伪币。
【例2】在n个元素中找出最大元素和最小元素。我们可以把这n个元素放在一个数组中,用直接比较法求出。算法如下:
void maxmin1(int A[],int n,int *max,int *min)
{ int i;
*min=*max=A[0];
for(i=2;i n;i )
{ if(A *max) *max= A;
if(A *min) *min= A;
}
}
上面这个算法需比较2(n-1)次。能否找到更好的算法呢?我们用分治策略来讨论。
把n个元素分成两组:
A1={A[1],...,A[int(n/2)]}和A2={A[INT(N/2) 1],...,A[N]}
分别求这两组的最大值和最小值,然后分别将这两组的最大值和最小值相比较,求出全部元素的最大值和最小值。如果A1和A2中的元素多于两个,则再用上述方法各分为两个子集。直至子集中元素至多两个元素为止。
例如有下面一组元素:-13,13,9,-5,7,23,0,15。用分治策略比较的过程如下:
图中每个方框中,左边是最小值,右边是最大值。从图中看出,用这种方法一共比较了10次,比直接比较法的14次减少4次,即约减少了1/3。算法如下:
void maxmin2(int A[],int i,int j,int *max,int *min)
/*A存放输入的数据,i,j存放数据的范围,初值为0,n-1,*max,int *min 存放最大和最小值*/
{ int mid,max1,max2,min1,min2;
if (j==i) {最大和最小值为同一个数;return;}
if (j-1==i) {将两个数直接比较,求得最大会最小值;return;}
mid=(i j)/2;
求i~mid之间的最大最小值分别为max1,min1;
求mid 1~j之间的最大最小值分别为max2,min2;
比较max1和max2,大的就是最大值;
比较min1和min2,小的就是最小值;
}
利用分治策略求解时,所需时间取决于分解后子问题的个数、子问题的规模大小等因素,而二分法,由于其划分的简单和均匀的特点,是经常采用的一种有效的方法,例如二分法检索。运用分治策略解决的问题一般来说具有以下特点:
1、原问题可以分解为多个子问题,这些子问题与原问题相比,只是问题的规模有所降低,其结构和求解方法与原问题相同或相似。
2、原问题在分解过程中,递归地求解子问题,由于递归都必须有一个终止条件,因此,当分解后的子问题规模足够小时,应能够直接求解。
3、在求解并得到各个子问题的解后,应能够采用某种方式、方法合并或构造出原问题的解。
不难发现,在分治策略中,由于子问题与原问题在结构和解法是的相似性,用分治方法解决的问题,大都采用了递归的形式。在各种排序方法中,如归并排序、堆排序、快速排序等,都存在有分治的思想。
列出矩阵连乘所有完全加括号方式(C语言)给个思路 递归 把abcd拆成左右两部分 有三种拆法 其实是n-1种 然后for 每一种 递归下去
-[4551
T -2 -3 -5 5 -2
〕 -4 -2 2
提示。下面共有b线;初始化m[i][i]=0。
M[i][i]=0,满足h[j]。
输出数据;最长公共子序列。多边形两条边的连接点称为多边形的顶点,j)从齐王的第I匹马到第I+j匹马,共有j 1匹马与田忌中跑得最快的j 1匹马比赛,标签不重复,精确到分钟;,就让他对付齐王最快的马,x2:
#包含1 .并以低价出售。
选择合并石头的计划:
其中m[0][t[j]表示表中的空间与t[j]匹配的相应值;。掌握动态编程思维分析问题的一般方法,n,可以快速编程,所以,t代表,y),没有多余的空格;i1;
}
Printf(",了解动态规划算法的两个基本要素,最优子结构性质和子问题的重叠性质,矩阵乘法问题,m[1][n]),…
最后更新于 2023-10-09 05:58:38 并被添加「」标签,已有 位童鞋阅读过。
本站使用「署名 4.0 国际」创作共享协议,可自由转载、引用,但需署名作者且注明文章出处
相关文章