例一:计算二项式系数:
在排列组合里面,我们有下面的式子(很容易用组合的定义来证明):
[img]http://dl.iteye.com/upload/attachment/0074/5221/2f21cf96-e6c5-3676-a114-3698fce0aec9.jpg[/img]
这个式子将C(n , k)的计算问题表述为了(问题描述)C(n-1 , k -1)和C(n -1, k)两个较小的重叠子问题。
运行:
C:\java>java Binomial
请输入n:
5
请输入k(0<=k<=n):
5
C[5,5] = 1
C[8,0] ———— 1
C[8,1] ———— 8
C[8,2] ———— 28
C[8,3] ———— 56
C[8,4] ———— 70
C[8,5] ———— 56
C[8,6] ———— 28
C[8,7] ———— 8
C[8,8] ———— 1
例二:斐波那契数列(动规实现)
无穷数列1,1,2,3,5,8,13,21,34,55,…,被称为Fibonacci数列。它可以递归地定义为:
[img]http://dl.iteye.com/upload/attachment/0074/5223/c61e2022-4aa8-3622-80e7-fa4d5287b8e8.jpg[/img]
2 程序实现
缓存是为了减少重复计算。
若求问题的唯一解(最优解),先分解成为子问题,而子问题的解也是唯一的(最优的)。子问题有重叠,为了减少重复计算,缓存重叠部分计算结果;
这两点也正是动规算法的精髓。实际上,这个例子是动规算法最简单的一个实例。
下载源代码。
在排列组合里面,我们有下面的式子(很容易用组合的定义来证明):
[img]http://dl.iteye.com/upload/attachment/0074/5221/2f21cf96-e6c5-3676-a114-3698fce0aec9.jpg[/img]
这个式子将C(n , k)的计算问题表述为了(问题描述)C(n-1 , k -1)和C(n -1, k)两个较小的重叠子问题。
/*
* 用动态规划算法计算C(n,k)
* 输入:一对非负整数n>=k>=0
* 输出:C(n,k)的值
*/
import java.util.*;
public class Binomial {
int C[][];
int Computing(int n,int k){
C = new int[n+1][n+1];
for(int i=0;i<=n;i++){
for(int j=0;j<=Math.min(i, k);j++){
if(j==0||j==i){
C[i][j] = 1;
}
else{
C[i][j] = C[i-1][j-1]+C[i-1][j];
}
}
}
return C[n][k];
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("请输入n:");
int n = in.nextInt();
System.out.println("请输入k(0<=k<=n):");
int k = in.nextInt();
Binomial b=new Binomial();
System.out.println("C["+n+","+k+"] = "+b.Computing(n, k));
for(int i = 0;i <= 8;i++)
System.out.println("C" + "[" + 8 + "," + i + "]" + " ———— " +b.Computing(8,i));
}
}
运行:
C:\java>java Binomial
请输入n:
5
请输入k(0<=k<=n):
5
C[5,5] = 1
C[8,0] ———— 1
C[8,1] ———— 8
C[8,2] ———— 28
C[8,3] ———— 56
C[8,4] ———— 70
C[8,5] ———— 56
C[8,6] ———— 28
C[8,7] ———— 8
C[8,8] ———— 1
例二:斐波那契数列(动规实现)
无穷数列1,1,2,3,5,8,13,21,34,55,…,被称为Fibonacci数列。它可以递归地定义为:
[img]http://dl.iteye.com/upload/attachment/0074/5223/c61e2022-4aa8-3622-80e7-fa4d5287b8e8.jpg[/img]
2 程序实现
缓存是为了减少重复计算。
import java.util.HashMap;
import java.util.Map;
public class FibonacciUtil {
static Map<Integer, Integer> cache = new HashMap<Integer, Integer>();
public static int fib(int n) {
if (n == 0 || n == 1)
return 1;
if (null != cache.get(n))
return cache.get(n);
int ret = fib(n - 1) + fib(n - 2);
cache.put(n, ret);
return ret;
}
public static void listFib(int n){
for(int i=1;i<n;i++){
System.out.print(fib(i)+",");
}
}
public static void main(String[] args) {
listFib(10);
}
}
若求问题的唯一解(最优解),先分解成为子问题,而子问题的解也是唯一的(最优的)。子问题有重叠,为了减少重复计算,缓存重叠部分计算结果;
这两点也正是动规算法的精髓。实际上,这个例子是动规算法最简单的一个实例。
下载源代码。