您的位置:首页 > 其它

【算法导论】第15章动态规划

2012-06-20 20:46 190 查看
1、问题引入

  

  和分治法一样,动态规划是通过组合子问题的解而解决整个问题的。分治法是指将问题划分成一些独立的子问题,递归求各个子问题,然后合并子问题的解而得到原问题的解。而动态规划适用于子问题不独立的情况,也就是各个子问题包含公共的“子子问题”,在这种情况下,分治法将不便于求解,而动态规划算法将对每个“子子问题”只求一次解,将其结果保存在一张表中,从而避免每次遇到各个子问题时重新计算答案。

  

  动态规划通常应用于最优化问题,此类问题可能有多种可行解,每个解有一个值,而我们希望找出一个具有最优值的解,称这样的解为该问题的“一个”最优解(而不是“确定的”最优解),因为可能存在多个取最优值的解。

  

  动态规划的设计可以分成如下4个步骤:

  (1)描述最优解的结构;

  (2)递归定义最优解的值;

  (3)按自底向上的方式计算最优解的值;

  (4)由计算结果构造一个最优解。

接下来将利用动态规划方法求解几个问题:装配线调度问题、矩阵链乘法问题、求最长的公共子序列问题、构造最优二叉查找树问题。

2、装配线调度

2.1 问题描述

  某汽车工厂有2个装配线,每个装配线有n 个装配站(按顺序编号1~n )标记为Si,j,表示第i个装配线的第j个装配站,两个装配线的对应的装配站执行相同的功能,但所用的时间可能不同。经过第i条流水线(i=1,2)的第j 个装配站所花的时间为a[i][j]。从第i条流水线的第j 个装配站移到第j+1个装配站的时间可以忽略,而移到另外一个流水线的下一个装配站则需要一定的时间t[i][j]。汽车进入流水线需要花时间,进入装配线1需要时间e[1],进入装配线2需要时间e[2]; 汽车出流水线时需要花时间,出装配线1需要时间x[1],出装配线2需要时间x[2] 。汽车的装配需要按顺序经过所有装配站。
  现在已知装配时间a[i][j] 、转移时间t[i][j]、进入装配线的时间e[i]、出装配线的时间x[i],要求输出装配一辆汽车所需要的最短时间,以及经过的装配站。

2.2 求解过程

(1)最优子结构

  对于装配线问题,推理如下:一条经过装配线S1,j的最快路径,必定是经过装配线1或2上的装配站j-1.因此通过S1,j的最快路径只能是以下二者之一:

    (a)通过装配站S1,j-1的最快路径,然后通过装配站S1,j;

     (b)通过装配站S2,j-1的最快路径,从装配线2移动到装配线1,然后通过装配站S1,j。

  对于装配线2,有类似结论。

(2)一个递归的解

  最终目标是确定通过工厂所有的装配线的最快时间,记为f*。设f[i][j]为一个汽车从起点到装配站Si,j的最快可能时间。汽车必然是经过装配线1或2最终到达装配站n,然后到达工厂的出口。即:

        f*=min(f[1]
+x[1] , f[2]
+x[2])

  要对f1
和f2
进行推理可以运用步骤1。

  初始化:f[1][1]=e[1]+a[1][1]

      f[2][1]=e[2]+a[2][1]

  计算f[i][j],其中j=2,3...,n;i=1,2

      f[1][j]=min( f[1][j-1]+a[1][j] , f[2][j-1]+t[2][j-1]+a[1][j])

      f[2][j]=min( f[2][j-1]+a[2][j] , f[1][j-1]+t[1][j-1]+a[2][j])

  为了便于跟踪最优解的构造过程,定义l[i][j]:i为装配线的编号,i=1,2 ,j表示装配站j-1被通过装配站Si,j的最快路线所使用,j=2,3,...,n;

(3)自底向上计算最优解的值

  用算法描述如下:

int fastestWay
f[1][1]=e[1]+a[1][1];
f[2][1]=e[2]+a[2][1];
for(j=2;j<n;j++)
{
if(f[1][j-1]+a[1][j]<=f[2][j-1]+t[2][j-1]+a[1][j])
{
f[1][j]=f[1][j-1]+a[1][j];
l[1][j]=1;
}
else
{
f[1][j]=f[2][j-1]+t[2][j-1]+a[1][j];
l[1][j]=2;
}

if(f[2][j-1]+a[2][j]<=f[1][j-1]+t[1][j-1]+a[2][j])
{
f[2][j]=f[2][j-1]+a[2][j];
l[2][j]=2;
}
else
{
f[2][j]=f[1][j-1]+t[1][j-1]+a[2][j];
l[2][j]=1;
}
}


2.3、具体实现代码如下:

View Code

#include<stdio.h>
#include<malloc.h>
#define max 9999
#define n 5

double optimalBst(double p[],double q[],int root[][n+1])
{
int i,j,l,r;
double t;
double w[n+2][n+1];
double e[n+2][n+1];
for(i=1;i<=n+1;i++)
{
e[i][i-1]=q[i-1];
w[i][i-1]=q[i-1];
}
for(l=1;l<=n;l++)
{
for(i=1;i<=n-l+1;i++)
{
j=i+l-1;
e[i][j]=max;
w[i][j]=w[i][j-1]+p[j]+q[j];
for(r=i;r<=j;r++)
{
t=e[i][r-1]+e[r+1][j]+w[i][j];
if(t<e[i][j])
{
e[i][j]=t;
root[i][j]=r;
}
}
}
}
return(e[1]
);
}
void printBst(int root[][n+1],int i,int j)
{
int k;
if(i<=j)
{
printf("%d  " ,root[i][j]);
k=root[i][j];
printBst(root,i,k-1);
printBst(root,k+1,j);
}
}
void main()
{
int i;
double k;
int root[n+1][n+1];
double p[n+1]={0,0.15,0.10,0.05,0.10,0.20};
double q[n+1]={0.05,0.10,0.05,0.05,0.05,0.10};
k=optimalBst(p,q,root);
printf("最小期望搜索代价为:%f\n",k);
printf("最优二叉查找树的中序遍历结果为:\n");
printBst(root,1,n);
}


  

  附:另外一个用动态规划求左右二叉查找树的程序:/article/5040489.html

6、有向无环图的单源最短路径长度(较简单)

  附:用动态规划求有向无环图的单源最短路径:/article/5040483.html

7、0-1背包问题

  附:用动态规划求0-1背包问题:/article/5040485.html

8、数塔

  附:用动态规划求数塔问题:/article/5040484.html

9、参考资料:

(1):http://blog.csdn.net/xiaoyjy/article/details/2420861

(2):算法导论

(3):c编程
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: