算法的独家记忆--动态规划

来源:互联网 发布:巡逻棒怎么写入数据 编辑:程序博客网 时间:2024/06/09 20:14

动态规划通常应用于最优解的问题,即在有多个解的问题中找到“一个”的最优解(这个解并非“确定不变”)。动态规划的核心:最优子结构和重叠子问题。

最优子结构:一个问题的最优解包含了子问题的最优解,通过解决子问题为整个问题的解决提供支持。

重叠子问题:通过每个子问题只解一次,把解保存在一个表中,让递归过程中重复的子问题跟快得到解决。

解题步骤:

1.找到问题的最优解结构。

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

3.自底向上计算最优解的值。

4.通过计算的最构造最优解。


大部分动态规划的问题的难点在于发现问题中最优解的递归过程。先承认自己没有天才的头脑,因此记下自己所遇的题的解法以满足一己私欲吧,下文中突兀的符号,不清楚的题意,丑陋的代码……望大家见谅。

《算法导论》

生产线问题:f1[i]表示到生产线1的i装备站的最优时间。a1[i]在生产线1的i装备站上花的时间。t1[i]表示从生产线1的i装备站移到另一条生产线所花的时间。对应还有数据f2[i],a2[i],t2[i]。e,x分别进入生产线和离开生产线的时间。

递归解:f1[j] = e1 + a1[1]                                               j=1;

                       =min(f1[j-1] + a1[j] , f2[j-1] + t2[j-1] + a1[j])      j>=2;

                f1[j] = e2 + a2[1]                                               j=1;

                       =min(f2[j-1] + a2[j] , f1[j-1] + t2[j-1] + a2[j])      j>=2;

实现:

public class ProductLine {/** * @author htorc */public static void main(String[] args) {int a1[] = {7,9,3,4,8,4};int a2[] = {8,5,6,4,5,7};int t1[] = {2,3,1,3,4};int t2[] = {2,1,2,2,1};int x[] = {3,2};int e[] = {2,4};int f1[] = new int[a1.length];int f2[] = new int[a1.length];    f1[0] = a1[0] + e[0];    f2[0] = a2[0] + e[1];    int i;    for(i=0; i<t1.length; i++){    f1[i+1] = Math.min(f1[i] + a1[i+1] , f2[i] + t2[i] + a1[i+1]);    f2[i+1] = Math.min(f1[i] + a2[i+1] + t1[i] , f2[i] + a2[i+1]);    }    System.out.println(Math.min(f1[i]+x[0], f2[i]+x[1]));}}

矩阵连乘:A0*A1……An适当添加括号使计算次数最少。  p[i],p[i+1]表示矩阵Ai的行数和列数。

递归解:m[i][j]表示Ai……Aj最少计算次数,s[i][j]表示分割点k的位置。

               m[i][j] = 0                                                                               i=j

                          = min{m[i][k] + m[k+1][j] + pi*pk*pj}( i<k<=j)        i<j

实现:

public class Matrix {/** * @author ht */public static void print(int[][] s, int i, int j){if(i == j)System.out.print("A" + i);else{System.out.print("(");print(s, i, s[i][j]-1);print(s, s[i][j], j);System.out.print(")");}}public static void main(String[] args) {int[] p = {30,35,15,5,10,20,25};long[][] m = new long[p.length-1][p.length-1];int[][] s = new int[p.length-1][p.length-1];long min_value,sum;int min_key;for(int i=0;i<p.length-1;i++){m[i][i] = 0;s[i][i] = 0;}for(int i=1; i<p.length-1; i++){for(int j=0; j<p.length-i-1; j++){min_value = Long.MAX_VALUE;min_key = j+1;for(int k=1; k<=i; k++){sum = m[j][j+k-1]+m[j+k][i+j] + p[j]*p[j+k]*p[i+j+1];if(sum<min_value){min_value = sum;min_key = j+k;}}m[j][j+i] = min_value;s[j][j+i] = min_key;}}System.out.println(m[0][p.length-2]);for(int i=0; i<p.length-1; i++){for(int j=0; j<p.length-1; j++){System.out.print(s[i][j] + " ");}System.out.println();}print(s,0,p.length-2);}}

最长公共子串:X = {x1,x2,^,xm} 和 Y = {y1,y2,^,ym} 最长的公共子串。例如 :“BCA”是X="ABCBDAB" Y="BDCABA"的公共子串,但不是最长的。

递归解:m[i][j]表示x的前i个数遇到y的前j个数是的最长子串长度。s[i][j]记录通过何种途径时x取到第i个数,y取到第j个数。

            m[i][j] = 0                                           i=0 || j=0;

                       = m[i-1][j-1] + 1                      x[i] = y[j];

                       = Max(m[i-1][j] , m[i][j-1])      x[i] != y[j];

            s[i][j] = 0       x[i-1] = y[j-1] ;            表示有公共元素加入,Zk-1是Xi-1和Yj-1的最长子串。

                     = 1       c[i-1][j] <= c[i][j-1] ;   表示X的前i个元素和Y的前j个组成的公共子集Zk蕴含Xi和Yj-1的一个最长子串。

                     = -1      c[i-1][j] <= c[i][j-1] ;   表示公共子集Zk蕴含Xi-1和Yj的一个最长子串。

实现:

public class LCS {/** * @author ht */public static void init(char[] x, char[] y, int[][] m, int[][] s){int l = x.length;int w = y.length;for(int i=0; i<=l; i++){m[i][0] = 0;s[i][0] = 0;}for(int j=0; j<=w; j++){m[0][j] = 0;s[0][j] = 0;}for(int i=1; i<=l; i++){for(int j=1; j<=w; j++){if(x[i-1] == y[j-1]){m[i][j] = m[i-1][j-1] + 1;s[i][j] = 0;} else {if(m[i][j-1] > m[i-1][j]){m[i][j] = m[i][j-1];s[i][j] = -1;} else {m[i][j] = m[i-1][j];s[i][j] = 1;}}}}}public static void print(char[] x,int[][] s,int i, int j){if(i==0 || j==0) return;if(s[i][j] == 0){print(x,s,i-1,j-1);System.out.print(x[i-1] + " ");} else if(s[i][j] == 1){print(x,s,i-1,j);} else {print(x,s,i,j-1);}}public static void main(String[] args) {char[] y = "BDCABA".toCharArray();char[] x = "ABCBDAB".toCharArray();int[][] m = new int[x.length+1][y.length+1];int[][] s = new int[x.length+1][y.length+1];init(x,y,m,s);print(x,s,x.length,y.length);/*for(int i=0; i<m.length; i++){for(int j=0; j<m[i].length; j++){System.out.print(s[i][j] + " ");}System.out.println();}*/}}


原创粉丝点击