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]; }

浙公网安备 33010602011771号