Algorithm 动态规划经典案例

一、0-1背包问题

public class _01KnapsackProblem {

    /**
     * Dynamic Programming
     * 动态规划转移方程
     * V(i,j) 表示i个物品装入j的容量的最大价值
     * V(i,0) = V(0,j) = 0
     * V(i,j) = V(i-1,j)  j<wi  
       V(i,j) = max{V(i-1,j) ,V(i-1,j-wi)+vi) } j>wi
           用j的体积装i-1个物品 或者 用j-wi的体积装i-1个物品且把第i个物品装入
     * 
     * 因此转移方程就是V(i,j) = max{V(i-1,j) ,V(i-1,j-wi)+vi) }
     * @param args
     */

    class Thing {
        double value;
        int volumn;
    }

    public double getMaxValue(Thing[] a, int n, int totalVolumn) {
        double V[][] = new double[n + 1][totalVolumn + 1];
        for (int i = 0; i <= n; i++) V[i][0] = 0;
        for (int j = 0; j <= totalVolumn; j++) V[0][j] = 0;
        //时间复杂度O(n*totalVolumn)
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= totalVolumn; j++) {
                if (a[i].volumn > j) {
                    V[i][j] = V[i - 1][j];
                } else {            
            V[i][j] = Math.max(V[i - 1][j], V[i - 1][j - a[i].volumn] + a[i].value); } } } return V[n][totalVolumn]; } public static void main(String[] args) { } }

 

二、矩阵链乘法

/**递推公式: C[i,j] = min{C[i,j],C[i,k-1] + C[k,j] + r[i]r[k]r[j+1]}*/
    public int matrixchain(int a[]){
        int len = a.length-1 ;
        int C[][] = new int[len+1][len+1];//从1开始计数
        for(int i=1;i<=len;i++ ) C[i][i] = 0;
        for(int d=1;d<=len-1;d++){//d是步长;必须从1开始;
            for(int i=1;i<=len-d;i++){
                int j = i+d; 
                C[i][j] = Integer.MAX_VALUE;
                for(int k=i+1;k<=j;k++)
                    C[i][j] = Math.min(C[i][j],C[i][k-1] + C[k][j] + a[i-1]*a[k-1]*a[j]);
            }
        }
        return C[1][len];
    }

 

三、编辑距离/Levenshtein Distance

public static int levenshtein(char[] one, char[] another) {
    if (one == null && another == null) {
        return 0;
    }
    if (one == null) {
        return another.length;
    }
    if (another == null) {
        return one.length;
    }
    int lena = one.length;
    int lenb = another.length;
    int[][] dp = new int[lena + 1][lenb + 1];
    for (int a = 0; a <= lena; a++) {
        dp[a][0] = a;
    }
    for (int b = 0; b <= lenb; b++) {
        dp[0][b] = b;
    }
    for (int a = 0; a < lena; a++) {
        for (int b = 0; b < lenb; b++) {
            if (one[a] != another[b]) {
                dp[a + 1][b + 1] = Math.min(Math.min(dp[a][b + 1], dp[a + 1][b]), dp[a][b]) + 1;
            } else {
                dp[a + 1][b + 1] = Math.min(Math.min(dp[a][b + 1], dp[a + 1][b]) + 1, dp[a][b]);
            }
        }
    }
    return dp[lena][lenb];
    //return StringUtils.getLevenshteinDistance(one.toString(), another.toString());
}

编辑距离转移方程:

如果a[i] == b[j] 则有 ED[i+1][j+1] = min(ED[i][j],ED[i][j+1]+1,ED[i+1][j]+1);

如果a[i] != b[j] 则有 ED[i+1][j+1] = min(ED[i+1][j], ED[i][j+1],ED[i][j])+1;

四、最长子序列(串)问题

五、扔鸡蛋问题

/**
     * 递推公式: DP[i][j] = min(1 + DP[k-1][j-1] + DP[i-k][j]);
     * //从第k层开始扔1次,然后k-1层h还有0次机会;
     * DP[i][0] = 1 + ... + i 从1楼往上扔
     * DP[0][j] = 0;
     * 扩展到2 DP[i][1] = min(1 + DP[k-1][0] + DP[i-k][1]);
     */
    public static int findFloor(int floors,int eggs){
        int  dp[][] = new int[floors+1][eggs];
        for(int i = 0;i<floors+1;i++) 
            Arrays.fill(dp[i], Integer.MAX_VALUE);
        for(int i = 0;i<eggs;i++) //0层不需要0次
            dp[0][i] = 0;
        for(int i = 1;i<floors+1;i++)//1个鸡蛋扔N层楼需要N次,一层层的往上递增
            dp[i][0] = i;
        for(int i = 1;i<floors+1;i++){
            for(int k= 1;k<=i;k++){
                /**求最少需要确定楼层所需要的最大的扔次数  
                 * 首先从第K层扔一下,如果K层破了,那么dp[k-1][0];
                 * 如果K层没有破,那么上面的i-K层还有两次扔的机会;
                 * 取两者的最大值+在第K层扔鸡蛋的1次
                 * 因此第K层的次数 dpk = 1 + Math.max(dp[k-1][0],dp[i-k][1])
                 * 显然从1~i之间,K的取值有i种,然后取这i中dpk的最小值作为dp[i][1];
                */
                dp[i][1] = Math.min(dp[i][1],1 + Math.max(dp[k-1][0],dp[i-k][1]));
            }
        }
        return dp[floors][eggs-1];
    }

六、。。。问题

posted @ 2016-01-03 15:23  √珞珈搬砖工√  阅读(142)  评论(0)    收藏  举报