每日一题(4)——动态规划《Introduction to Algorithms》总结篇

概述

同分治法一样动态规划是通过组合子问题的解而解决整个问题的

动态规划的4个步骤:

1.描述最优解结构;

2.递归定义最优解的值;

3.按自底向上方式计算最优解;

4.由计算出的结果构造最优解;(1-3步是基础,第4步可以略去)

 

动态规划特点,包含重复子问题,可以用图结构保存中间结果,不用重复计算。

 

1.装配线调度

(PS:这图太磕碜了,没办法,原来网页版的算法导论在PKU的服务器上有,现在不让访问了,悲剧啊,NB学校就是NB,我等P民只能仰望啊~闲扯啊,各位看官将就着看吧~)

 

问题:每个车间生产需要生产时间,从不同的生产线调配到另一个生产线需要调配时间,计算最小时间?

1.描述最优解结构(划分子问题,子结构):按生产线长度划分;

2.递归定义最优解的值:递归求解每个长度的最优解;

3.按自底向上方式计算最优解,按长度从短到长求解;

 

输入:生产线长度,每个车间的生产时间,每个车间之间的调度时间,

输出:最短长度;

example:

Input:

6

7 9 3 4 8 4
8 5 6 4 5 7
2 3 1 3 4
2 1 2 2 1

output

38

  1. #include <iostream>  
  2.   
  3. using namespace std;  
  4.   
  5. int minT[2][100];  
  6. int a[2][100], t[2][100];  
  7. int e[2]={2,4}, x[2]={3,2};  
  8.   
  9. int cal( int k, int num)  
  10. {  
  11.     if (num==1)   
  12.     {  
  13.         minT[k][1] = e[k]+a[k][1];  
  14.         return minT[k][1];  
  15.     }  
  16.     if(minT[k][num]>0) return minT[k][num];  
  17.     else  
  18.     {  
  19.         minT[k][num] = min(cal(k, num-1), cal((k+1)%2, num-1)+t[(k+1)%2][num-1] )+a[k][num];  
  20.         return minT[k][num];  
  21.     }  
  22. }  
  23.   
  24. int main()  
  25. {  
  26.     memset(minT, 0, sizeof(minT));  
  27.     int count;  
  28.     cin>>count;  
  29.     cout<<"a & t: "<<endl;  
  30.     for(int i=1 ;i<=count; i++) cin>>a[0][i];  
  31.     for(int i=1 ;i<=count; i++) cin>>a[1][i];  
  32.     for(int i=1 ;i<=count-1; i++) cin>>t[0][i];  
  33.     for(int i=1 ;i<=count-1; i++) cin>>t[1][i];  
  34.   
  35.   
  36.     int minCost = min(cal(0,count)+x[0] ,cal(1,count)+x[1]);  
  37.   
  38.     cout<<"MIN:"<<minCost<<endl;  
  39. }  


 

2.矩阵链乘法

n个矩阵连乘,A1,A2,A3,... An;  相乘的顺序不同,

A1,A2,A3,A4会产生5种不同的组合:

1.(A1 (A2 (A3*A4) ) )  2. (A1 ( (A2*A3) A4) )  3. ( (A1*A2)(A3*A4) )  4.( ( (A1(A2*A3) )A4 )  5.(((A1*A2) A3) A4)

根据不同的组合,计算相乘的次数也不同

要求输出最小相乘次数

  

输入

矩阵数;(一个值 n)

矩阵的横纵坐标:(n+1个值 )因为后矩阵的行数等于前坐标的列数

要求计算区间:

输出:

区间的最小计算次数

 

for example:

输入:

6

30 35 15 5 10 20 25

1 6

输出:

15125

 

1.描述最优解结构(划分子问题,子结构):按组合划分;

2.递归定义最优解的值:递归求解每组合的最优解;(并保存在矩阵的相应位置中)

3.按自底向上方式计算最优解,按区间从短到长求解;(可以不断调用矩阵,如果矩阵中有的话)

动态规划方程

s[i,j]=0 (if i=j);

s[i,j]=s[i,k]+s[k+1,j]+p[i-1]p[k]p[j];

 

  1. #include <iostream>  
  2.   
  3. using namespace std;  
  4. #define INF 1000000000;  
  5.   
  6. double s[100][100];  
  7. int p[101];  
  8.   
  9. double minMul(int low, int high)  
  10. {  
  11.     if(low==high) return 0;  
  12.     if(s[low][high]>0) return s[low][high];  
  13.     double minTmp = INF;  
  14.     double tmp;  
  15.     for (int k=low; k<high; k++)  
  16.     {  
  17.         tmp=minMul(low,k)+minMul(k+1,high)+p[low-1]*p[k]*p[high];  
  18.         if(tmp<minTmp)  
  19.             minTmp = tmp;  
  20.     }  
  21.     s[low][high]=minTmp;  
  22.     return minTmp;  
  23. }  
  24.   
  25. int main()  
  26. {  
  27.     memset(s,0,sizeof(s));  
  28.     int n;  
  29.     cin>>n;  
  30.     for(int i=0; i<=n; i++) cin>>p[i];  
  31.     int left,right;  
  32.     cin>>left>>right;  
  33.     double minM = minMul(left,right);  
  34.     cout<<minM<<endl;  
  35.   
  36. }  

 

 

3.最长公共子序列

给出两个序列,要求给出这两个序列中的最长公共子序列长度;可以不连续,但必须按顺序

a="ABCBDAB", b="BDCABA" 的最长公共子序列长度为4,为"BCBA"

 

典型的使用矩阵保存中间值,向上不断求解最优解(相同类型:求解字符串间最短距离)

 

动态规划方程:

 if(i==0 或 j==0)

        当f(a[i]==b[j])时 A[i][j]=1;否则 A[i][j]=0;
 else:

       当f(a[i]==b[j])时 A[i][j]=A[i-1][j-1]+1; 否则 A[i][j]=max(A[i-1][j], A[i][j-1]);

  1. #include <iostream>  
  2. #include <string>  
  3.   
  4. using namespace std;  
  5.   
  6. string a="ABCBDAB", b="BDCABA";  
  7. int A[100][100];  
  8.   
  9. int main()  
  10. {  
  11.     int la = a.length();  
  12.     int lb = b.length();  
  13.     for(int i=0; i<la; i++)  
  14.     {     
  15.         for(int j=0; j<lb; j++)  
  16.         {  
  17.             if(i==0 || j==0)  
  18.             {  
  19.                 if(a[i]==b[j]) A[i][j]=1;  
  20.                 else A[i][j]=0;  
  21.             }  
  22.             else  
  23.             {  
  24.                 if(a[i]!=b[j]) A[i][j] = max(A[i-1][j], A[i][j-1]);  
  25.                 else A[i][j]=A[i-1][j-1]+1;  
  26.             }  
  27.         }  
  28.     }  
  29.     cout<<A[la-1][lb-1]<<endl;  
  30. }  

 

 

4.构造最优二叉查找树

每个节点具有一个期望p,每个叶子节点具有一个期望q,要构造一棵二叉树使得总体查找期望最小。

每个节点具有一个期望p,每个叶子节点具有一个期望q,要构造一棵二叉树使得总体查找期望最小。

Input

6
0.15 0.1 0.05 0.1 0.2
0.05 0.1 0.05 0.05 0.05 0.1 

 

动态规划方程:

概率和:

W(i,j)=q(j) (if i>j 叶子节点)

W(i,j)=W(i,r-1)+p(r)+W(r+1,j)

查找期望:

E(i,j)=W(i,j)(if i>j 叶子节点)

E(i,j)=E(i,r-1)+w(i,j)+E(r+1,j)

 

 

 

  1. #include <iostream>  
  2. #define INF 1000000;  
  3. using namespace std;  
  4.   
  5. float p[100],q[100];  
  6. float w[100][100], e[100][100];  
  7.   
  8. float calW(int i, int j)  
  9. {  
  10.     if(w[i][j]>0) return w[i][j];  
  11.     if(i > j)  
  12.     {  
  13.         w[i][j] = q[j];  
  14.         return w[i][j];  
  15.     }  
  16.   
  17.     float minw=INF;  
  18.     for (int r=i; r<=j; r++)  
  19.     {  
  20.         w[i][j] = calW(i,r-1)+p[r]+calW(r+1,j);  
  21.         if(w[i][j]<minw) minw = w[i][j];  
  22.     }  
  23.     w[i][j] = minw;  
  24.     return w[i][j];  
  25. }  
  26.   
  27. float calE(int i, int j)  
  28. {  
  29.     if(e[i][j]>0) return e[i][j];  
  30.     if(i>j)   
  31.     {  
  32.         e[i][j] = calW(i,j);  
  33.         return e[i][j];  
  34.     }  
  35.   
  36.     float minE=INF;  
  37.     for (int r=i; r<=j; r++)  
  38.     {  
  39.         e[i][j] = calE(i, r-1)+calW(i, j)+calE(r+1, j);  
  40.         if(e[i][j]<minE) minE = e[i][j];  
  41.     }  
  42.     e[i][j] = minE;  
  43.     return e[i][j];  
  44. }  
  45.   
  46. int main()  
  47. {  
  48.     int n;  
  49.     memset(p,0,sizeof(p));  
  50.     memset(q,0,sizeof(q));  
  51.     cin>>n;  
  52.     for (int i=1; i<n; i++) cin>>p[i];     //non-leaf  
  53.     for (int j=0; j<n; j++) cin>>q[j]; //leaf  
  54.       
  55.     float all15=calE(1,5);  
  56.     cout<<all15<<endl;  
  57.   
  58. }  


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值