动态规划:
拿LCS举例,设两个字符段为X,Y,当x[i]==y[j]时, c[i,j]=k为LCS。
算法为:
LCS(x,y,i,j){
if(x[i]==y[j])
then c[i.j]=LCS(x,y,i-1,j-1)+1;
else c[i,j]=max{LCS(x,y,i-1,j),LCS(x,y,i,j-1)};
return c[i,j];
}
此算法像树
结合备忘法理解LCS:
LCS(x,y,i,j){
if(c[i,j]==null)
then if(x[i]==y[j])
then c[i.j]=LCS(x,y,i-1,j-1)+1;
else c[i,j]=max{LCS(x,y,i-1,j),LCS(x,y,i,j-1)};
return c[i,j];
}
备忘法即为了节省时间,将相同的工作省略,用备忘记录结果
图示:
A B C B D A B
0 0 0 0 0 0 0
B 0 0 1 1 1 1 1 1
D 0 0 1 1 1 2 2 2
C 0 0 1 2 2 2 2 2
A 0 1 1 2 2 2 3 3
B 0 1 2 2 3 3 3 4
A 0 1 2 2 3 3 4 4
根据备忘法公式得到的表格例子
第一行和第一列为初始值0,如按公式将绿色字体比较取 MAX ,得到蓝色字体结果
红色字体从左到右自上而下的顺序即为寻找LCS的顺序,最后结果为4,序列为BCBA,当然这个结果不唯一,一般题目都会给出要求限制。
以下是度娘上的:
1.将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。保存已解决的子问题的答案,在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。具体的动态规划算法多种多样,但它们具有相同的填表格式。
2.给定k阶段状态变量x(k)的值后,如果这一阶段的决策变量一经确定,第k+1阶段的状态变量x(k+1)也就完全确定,即x(k+1)的值随x(k)和第k阶段的决策u(k)的值变化而变化,那么可以把这一关系看成(x(k),u(k))与x(k+1)确定的对应关系,用x(k+1)=Tk(x(k),u(k))表示。这是从k阶段到k+1阶段的状态转移规律,称为状态转移方程。
基本结构
基本模型
顺推:f[Uk]=opt{f[Uk-1]+L[Uk-1,Xk-1]} 其中, L[Uk-1,Xk-1]: 状态Uk-1通过策略Xk-1到达状态Uk 的费用 初始f[U1];结果:f[Un]。
f[Uk]=opt{f[Uk+1]+L[Uk,Xk]}
L[Uk,Xk]: 状态Uk通过策略Xk到达状态Uk+1 的费用
初始f[Un];结果:f(U1)
适用条件
作用
搜索
int f(int i, int j, int (*a)[4])
{
int f1, f2, tmp=0, k;
if(i==0||j==0)
return a[0][0];
if(j==i)
{
for(k=0;k<=i;k++)
tmp+=a[k][k];
return tmp;
}
f1=f(i-1, j, a);
f2=f(i-1, j-1, a);
if(f1<f2)
return f2+a[i][j];
else
return f1+a[i][j];
}
显而易见,这个算法就是最简单的搜索算法。时间复杂度为2^n,明显是会超时的。分析一下搜索的过程,实际上,很多调用都是不必要的,也就是把产生过的最优状态,又产生了一次。为了避免浪费,很显然,我们存放一个opt数组: Opt[i, j] - 每产生一个f(i, j),将f(i, j)的值放入opt中,以后再次调用到f(i, j)的时候,直接从opt[i, j]来取就可以了。于是动态规划的状态转移方程被直观地表示出来了,这样节省了思维的难度,减少了编程的技巧,而运行时间只是相差常数的复杂度,避免了动态规划状态转移先后的问题,而且在相当多的情况下, 递归算法能更好地避免浪费,在比赛中是非常实用的。
for(inti=n-1;i>=1;--i)//从倒数第二行开始
{
for(intj=1;j<=i;j++)
{
if(a[i+1][j][1]>a[i+1][j+1][1])//左边大
{
a[i][j][2]=0;//选择左边
a[i][j][1]+=a[i+1][j][1];
}
else//右边大
{
a[i][j][2]=1;//选择右边
a[i][j][1]+=a[i+1][j+1][1];
}