动态规划:dynamic programming
dp:
最优子结构
重叠子问题
独立子问题
步骤:
1.描述一个最优子结构
2.递归定义最优解
3.自底向上求出最优解的值
4.按要求求出一个最优解
其时间效率为: 有多少子问题*这些子问题分别有多少选择
总结:还挺好玩,感觉和高中的推理差不多,只是要深植于 找到特征+找到最优子结构+描述最优子结构+递归定义+求解+加上路径数组来构造最优解。
从前几项的关系得出推理:
从本问题可以被分为几个问题来得出推理
从要求的最后一项往前推
装配线调度:
1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 int main() 7 { 8 int e1,e2,x1,x2,a1[7],a2[7]; 9 int f[2][7],fe,le,l[2][7],t1[7],t2[7]; 10 scanf("%d%d",&e1,&e2); 11 scanf("%d%d",&x1,&x2); 12 for(int i=1;i<=6;i++) 13 scanf("%d",&a1[i]); 14 for(int i=1;i<=6;i++) 15 scanf("%d",&a2[i]); 16 for(int i=1;i<=5;i++) 17 scanf("%d",&t1[i]); 18 for(int i=1;i<=5;i++) 19 scanf("%d",&t2[i]); 20 f[1][1]=e1+a1[1]; 21 f[2][1]=e2+a2[1]; 22 23 for(int j=2;j<=6;j++) 24 { 25 if(f[1][j-1]+a1[j]<=f[2][j-1]+t2[j-1]+a1[j]) 26 { 27 f[1][j]=f[1][j-1]+a1[j]; 28 l[1][j]=1; 29 } 30 else 31 { 32 f[1][j]=f[2][j-1]+t2[j-1]+a1[j]; 33 l[1][j]=2; 34 } 35 36 if(f[2][j-1]+a2[j]<=f[1][j-1]+t1[j-1]+a2[j]) 37 { 38 f[2][j]=f[2][j-1]+a2[j]; 39 l[2][j]=2; 40 } 41 else 42 { 43 f[2][j]=f[1][j-1]+t1[j-1]+a2[j]; 44 l[2][j]=1; 45 } 46 } 47 if(f[1][6]+x1<=f[2][6]+x2) 48 { 49 fe=f[1][6]+x1; 50 le=1; 51 } 52 else 53 { 54 fe=f[2][6]+x2; 55 le=2; 56 } 57 58 printf("%d\n",fe); 59 60 int i=le; 61 printf("print line %d,station %d\n",i,6); 62 for(int j=6;j>=2;j--) 63 { 64 i=l[i][j]; 65 printf("print line %d,station %d\n",i,j-1); 66 } 67 return 0; 68 }
矩阵链乘法
节省了常数递归时间,还可以根据存取模式进行求解。
1 #include <iostream> 2 #include <cstdio> 3 #define inf 1e9 4 using namespace std; 5 int s[7][7]; 6 void print_optimal_parens(int i,int j) 7 { 8 if(i==j) 9 printf("A%d",i); 10 else 11 { 12 printf("("); 13 print_optimal_parens(i,s[i][j]); 14 print_optimal_parens(s[i][j]+1,j); 15 printf(")"); 16 } 17 18 } 19 20 int main() 21 { 22 int p[7]; 23 for(int i=0;i<=6;i++) 24 scanf("%d",&p[i]); 25 26 int m[7][7]; 27 for(int i=1;i<=6;i++) 28 m[i][i]=0; 29 for(int l=2;l<=6;l++) 30 { 31 for(int i=1;i<=6-l+1;i++) 32 { 33 int j=i+l-1; 34 m[i][j]=inf; 35 for(int k=i;k<=j-1;k++) 36 { 37 int q=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j]; 38 if(q<m[i][j]) 39 { 40 m[i][j]=q; 41 s[i][j]=k; 42 } 43 } 44 } 45 } 46 printf("%d\n",m[1][6]); 47 48 print_optimal_parens(1,6); 49 return 0; 50 }
做备忘录的自顶向下的递归法时间效率O(n^3)
可以对一些子问题根本不需要求解的问题避免求解。
1 #include <iostream> 2 #include <cstdio> 3 #define inf 1e9 4 using namespace std; 5 int s[7][7]; 6 int p[7]; 7 int m[7][7]; 8 void print_optimal_parens(int i,int j) 9 { 10 if(i==j) 11 printf("A%d",i); 12 else 13 { 14 printf("("); 15 print_optimal_parens(i,s[i][j]); 16 print_optimal_parens(s[i][j]+1,j); 17 printf(")"); 18 } 19 20 } 21 22 int lookup_chain(int i,int j) 23 { 24 if(m[i][j]<inf) 25 return m[i][j]; 26 if(i==j) 27 m[i][j]=0; 28 for(int k=i;k<=j-1;k++) 29 { 30 int q=lookup_chain(i,k)+lookup_chain(k+1,j)+p[i-1]*p[k]*p[j]; 31 if(q<m[i][j]) 32 { 33 m[i][j]=q; 34 s[i][j]=k; 35 } 36 } 37 return m[i][j]; 38 } 39 40 void memorzed_matrix_chain() 41 { 42 for(int i=1;i<=6;i++) 43 for(int j=i;j<=6;j++) 44 m[i][j]=inf; 45 lookup_chain(1,6); 46 } 47 48 49 50 51 int main() 52 { 53 for(int i=0;i<=6;i++) 54 scanf("%d",&p[i]); 55 memorzed_matrix_chain(); 56 printf("%d\n",m[1][6]); 57 58 print_optimal_parens(1,6); 59 return 0; 60 }
最长公共子序列的实现算法:加打印最优解
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 6 using namespace std; 7 8 void print_lcs(int b[][5],char x[],int i,int j) 9 { 10 if(i==-1 || j==-1) 11 return; 12 if(b[i][j]==1) 13 { 14 printf("%c",x[i]); 15 print_lcs(b,x,i-1,j-1); 16 } 17 else if(b[i][j]==2) 18 print_lcs(b,x,i-1,j); 19 else if(b[i][j]==3) 20 print_lcs(b,x,i,j-1); 21 22 } 23 int lcs(char x[],char y[]) 24 { 25 int m=strlen(x); 26 int n=strlen(y); 27 int c[m+1][n+1]; 28 int b[8][5]; 29 for(int i=0;i<=m;i++) 30 c[i][0]=0; 31 for(int i=0;i<=n;i++) 32 c[0][i]=0; 33 34 for(int i=0;i<m;i++) 35 { 36 for(int j=0;j<n;j++) 37 { 38 if(x[i]==y[j]) 39 { 40 c[i+1][j+1]=c[i][j]+1; 41 b[i][j]=1; 42 } 43 44 else if(c[i][j+1]>=c[i+1][j]) 45 { 46 c[i+1][j+1]=c[i][j+1]; 47 b[i][j]=2; 48 } 49 else if(c[i][j+1]<c[i+1][j]) 50 { 51 c[i+1][j+1]=c[i+1][j]; 52 b[i][j]=3; 53 } 54 } 55 } 56 print_lcs(b,x,m-1,n-1); 57 puts(""); 58 return c[m][n]; 59 } 60 int main() 61 { 62 char x[]="ABCBDAB"; 63 char y[]="ABCB"; 64 int LCS=lcs(x,y); 65 printf("%d\n",LCS); 66 return 0; 67 }
最优二叉搜索树
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #define inf 0x3f3f3f3f 6 using namespace std; 7 8 9 float optimal_bst(float p[],float q[],int n) 10 { 11 float e[n+2][n+2],w[n+2][n+2]; 12 int root[7][7]; 13 14 for(int i=1;i<=n+1;i++) 15 { 16 e[i][i-1]=q[i-1]; 17 w[i][i-1]=q[i-1]; 18 } 19 20 for(int l=1;l<=n;l++) 21 { 22 for(int i=1;i<=n-l+1;i++) 23 { 24 int j=i+l-1; 25 e[i][j]=inf; 26 w[i][j]=w[i][j-1]+p[j]+q[j]; 27 for(int r=i;r<=j;r++) 28 { 29 float t=e[i][r-1]+e[r+1][j]+w[i][j]; 30 if(t<e[i][j]) 31 { 32 e[i][j]=t; 33 root[i][j]=r; 34 } 35 } 36 } 37 } 38 return e[1][n]; 39 } 40 41 42 int main() 43 { 44 float q[7],p[7]; 45 for(int i=1;i<=5;i++) 46 scanf("%f",&p[i]); 47 for(int i=0;i<=5;i++) 48 scanf("%f",&q[i]); 49 printf("%f\n",optimal_bst(p,q,5)); 50 return 0; 51 }