算法回顾 之 动态规划

image

动态规划的核心是最优子结构原理(Optimal substructure), 最优子结构表示如下:
    设 问题( C, N={1,2,...,n}, {wi}i∈N, {vi}i∈N ) 的最优解是 (y1,y2,...,yn), 那么
    (y2,...,yn)是 问题( C-w1, N={2,...,n}, {wi}i∈N, {vi}i∈N ) 的最优解

 

动态规划经典算法有:
1.  数字三角形问题
2.  最长公共子序列问题
3.  字符串的编辑距离    

… …

1. 数字三角形问题
        7
       3 8
      8 1 0
     2 7 4 4
    4 5 2 6 5
找出一条从顶点至底部的路径,使该路径经过的数字总和最大(每个数只能到达其左下或右下的相邻数字)
用二维数组a存放数字三角形

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

int[][] b=new int[a.length][a[0].length];
//...
b[0][0]=a[0][0];
for(int i=1;i<a.length;i++){
    for(int j=0;j<a[0].length;j++){
        if(j==0){
            b[i][j]=a[i][j]+b[i-1][j];
        }
        else{
            b[i][j]=(a[i][j]+b[i-1][j-1]) > (a[i][j]+b[i-1][j]) ? (a[i][j]+b[i-1][j-1]) : (a[i][j]+b[i-1][j]);
        }
    }
}
//...

遍历b数组的最底层, 最大值即最大路径长度。

 

2. 最长公共子序列问题
例如:
image 
又如:
序列一 1,2,3,4,5,6,7,8,9,10,11
序列二 1,7,8,9,2,3,5,6,4,11,10
两序列的最长公共子序列为:1,2,3,5,6,11或1,2,3,5,6,10, 长度为6


解: 设c[x,y,i,j]表示 数组x从x[0]~x[i] 与 数组y从y[0]~y[j] 的最长公共子序列的长度, 那么, 有:
c[x,y,i,j]=0                                                 if   i<0 || j<0
c[x,y,i,j]=c[x,y,i-1,j-1]+1                              if   i>=0, j>=0, x[i]==y[j]
c[x,y,i,j]=max{ c[x,y,i-1,j] , c[x,y,i,j-1] }         if   i>=0, j>=0, x[i]!=y[j]

代码如下:

public static int trying(int[] A, int[] B, int i, int j){
    if(i<0||j<0){
        return 0;
    }
    else if(A[i]==B[j]){
        return trying(A,B,i-1,j-1)+1;
    }
    else{
        return Math.max(trying(A,B,i-1,j),trying(A,B,i,j-1));
    }
}

 

3. 字符串的编辑距离
将字符串A变换为字符串B所用的最少删除、插入、替换操作数称为字符串A到B的编辑距离, 记为d(A, B) , 设两个字符串为A[1:m]和B[1:n],
设D[i, j]=d(A[1:i], B[1:j])。
单字符a, b的编辑距离为:
d(a, b)=0    if a==b
d(a, b)=1    if a!=b
那么, D[i, j]可以递归地定义为: D[i, j]=min{ D[i-1,j-1]+d(A[i], B[j]) , D[i-1, j]+1 , D[i, j-1]+1 }
代码如下:

public static int isEqual(char a, char b){
    if(a==b)
        return 0;
    else
        return 1;
}
 
public static int Min(int a, int b, int c){
    int min=Math.min(a,b);
    return Math.min(min,c);
}
 
//A[0:i]与B[0:j]的编辑距离
public static int findDistance(int i, int j){
    if(i==0 && j==0){
        return isEqual(A.charAt(i), B.charAt(j));
    }
    else if(i!=0 && j!=0){
        return Min(findDistance(i-1,j)+1, findDistance(i,j-1)+1, findDistance(i-1,j-1)+isEqual(A.charAt(i), B.charAt(j)));
    }
    else{
        if(i==0){
            if(isEqual(A.charAt(i), B.charAt(j))==0)
                return j;
            else
                return findDistance(i,j-1)+1;
        }
        else{
            if(isEqual(A.charAt(i), B.charAt(j))==0)
                return i;
            else
                return findDistance(i-1,j)+1;
        }
    }
}
posted @ 2011-09-17 22:02  Chen.  Views(199)  Comments(0Edit  收藏  举报