动态规划主要用于求解包含重叠子问题的最优化问题的方法。其基本思想是,将原问题分解为相似的子问题,在求解的过程中通过子问题的解求出原问题的解。
应用动态规划有两个基本条件:
1.最优子结构
将问题分解为子问题,子问题最优解决定全局最优解。
2.子问题重叠性质
子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。
动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格(数组)中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。
通常动态规划算法有两种方式:自顶向下和自底向上。
1.自顶向下
是一种递归前进的设计策略。递归步骤首先查看数组中是否存在已被计算的结果。如果存在,直接返回此结果,如果不存在,那么递归就首先执行计算,然后将计算结果写入数组。这样可以使得后面的递归步骤能够对其进行访问。自顶向下编程也被称为:记忆(memorization)。
2.自底向上
将递归算法替换为使用存储容器和迭代的算法。它从最底层顺序填充容器(数组),迭代过程每个步骤都是用先前计算好的值来计算下一个值。
/**
* dynamic programming
* @author wll
*
*/
public class DynamicProgramming {
public static void main(String[] args) {
int result=binomial(88,7);
System.out.println(result);
//----------------------------
final int NUM = 40;
int[]flist=new int[NUM+1];
int f=fibDynamic(NUM,flist);
System.out.println(f);
//-----------------------------
int f2=fibDynamic2(NUM);
System.out.println(f2);
}
/**bottom-up dynamic programming
* compute C(n,k) with time efficiency O(n)
*
* @return return C(n,k)
*/
private static int binomial(int n,int k){
//create an n+1 by k+1 matrix
int[][]C=new int[n+1][k+1];
//rows range from 0 through n
for(int i=0;i<=n;i++){
int min=i>k?k:i;
//only generate columns 0 through min
for(int j=0;j<=min;j++){
//C[i][j]=1 when j==0 or j==i
if(j==0 || j==i)
C[i][j]=1;
else
C[i][j]=C[i-1][j-1]+C[i-1][j];
}
}
//return the entry C(n,k)
return C[n][k];
}
/**
* up-bottom dynamic programming
* @param n
* @param fibs
* @return
*/
private static int fibDynamic(int n,int[]fibs)
{
//initialize the value with -1
int fibValue=-1;
//first search the array
if(fibs[n]>0)
return fibs[n];
//n==0 set fibValue 0;
//n==1 set fibValue 1
if(n<=1)
fibValue=n;
else
fibValue=fibDynamic(n-1,fibs)+fibDynamic(n-2,fibs);
//set the value fibValue to fibs[n]
fibs[n]=fibValue;
//return the entry fib(n)
return fibValue;
}
/**
* bottom-up dynamic programming
* @param n
* @return the result of fibonacci
*/
private static int fibDynamic2(int n)
{
//create an n+1 array
int[]fibs=new int[n+1];
//initialize
fibs[1]=1;
fibs[2]=1;
//range from 3 through n
for(int i=3;i<=n;i++)
{
//fill the array,generate fibs(i)
fibs[i]=fibs[i-1]+fibs[i-2];
}
return fibs[n];
}
/**
* recursive method with low efficiency.
* compute the value of C(n,k)
*
* @param n
* @param k
* @return the result of C(n,k)
*/
private static int binomial2(int n,int k){
if(k>n)
throw new
IllegalArgumentException("wrong arguments!!!");
//C(n,k)==1 when k==0 or n==k
if(k==0 || n==k)
return 1;
else
return binomial2(n-1,k-1)+binomial2(n-1,k);
}
}