算法-动态规划
2015-06-04 14:52
330 查看
动态规划最重要的就是定义问题的状态。
定义出问题状态之后,可以通过对简单例子的推导,得到状态转移方程。之后的东西就简单多了。
例如:
有m*n的方格,每个方格存放了若干个苹果。
从左上角的格子开始,只能向右或者向下走,每走到一个格子,就把格子内的苹果收集起来,
这样下去,你最多能收集到多少苹果?
分析:
定义状态为d[i,j],表示在i*j方格内,最多收集的苹果数。
A[i,j]表示在行数为i,列数为j的方格内存放的苹果数。
先从最简单的情况开始分析
d[1,1] = A[0,0] 在1*1的方格内,最多收集到的苹果数就是存放在A[0,0]处的苹果数。
d[1,2] = A[0,0] + A[0,1] = d[1,1]+A[0,1]
d[1,3] = A[0,0] + A[0,1] +A[0,2] = d[1,2]+A[0,2]
d[2,2] = A[0,0] + A[0,1] + A[1,1] = d[1,2] + A[1,1]
或者
d[2,2] = A[0,0] + A[1,0] + A[1,1] = d[2,1] + A[1,1]
因此d[2,2] = max(d[1,2], d[2,1])+A[1,1]
可以得到d[i,j] = max{d[i-1,j], d[i,j-1]}+A[i-1,j-1];
代码如下:
带备忘录的递归算法也可以是一种动态规划算法,这个在《算法的乐趣》中有提到,也是一种非常方便直观的方法。
参考:
1.《算法的乐趣》
2. http://www.hawstein.com/posts/dp-novice-to-advanced.html
定义出问题状态之后,可以通过对简单例子的推导,得到状态转移方程。之后的东西就简单多了。
例如:
有m*n的方格,每个方格存放了若干个苹果。
从左上角的格子开始,只能向右或者向下走,每走到一个格子,就把格子内的苹果收集起来,
这样下去,你最多能收集到多少苹果?
分析:
定义状态为d[i,j],表示在i*j方格内,最多收集的苹果数。
A[i,j]表示在行数为i,列数为j的方格内存放的苹果数。
先从最简单的情况开始分析
d[1,1] = A[0,0] 在1*1的方格内,最多收集到的苹果数就是存放在A[0,0]处的苹果数。
d[1,2] = A[0,0] + A[0,1] = d[1,1]+A[0,1]
d[1,3] = A[0,0] + A[0,1] +A[0,2] = d[1,2]+A[0,2]
d[2,2] = A[0,0] + A[0,1] + A[1,1] = d[1,2] + A[1,1]
或者
d[2,2] = A[0,0] + A[1,0] + A[1,1] = d[2,1] + A[1,1]
因此d[2,2] = max(d[1,2], d[2,1])+A[1,1]
可以得到d[i,j] = max{d[i-1,j], d[i,j-1]}+A[i-1,j-1];
代码如下:
#define ROW (3) #define COL (3) int max(int a, int b) { return (a > b) ? a : b; } int d[ROW+1][COL+1]; int collect_apple(int M[ROW][COL], int m, int n) { if ((m <= 0)||(n <= 0)||(NULL == M)) { return 0; } int i = 0; int j = 0; for (i = 0; i <= m; i++) { d[i][0] = 0; } for (j = 0; j <= n; j++) { d[0][j] = 0; } for (i = 1; i <= m; i++) { for (j = 1; j <= n; j++) { int t1 = d[i-1][j]; int t2 = d[i][j-1]; int tmax = max(t1, t2); d[i][j] = tmax + M[i-1][j-1]; } } return d[m] ; } int collect_apple_demo() { int table[ROW][COL] = {{2, 9, 5}, {4, 5, 5}, {2, 7, 9}}; int apple = collect_apple(table, ROW, COL); printf("apples:%d\n", apple); collect_apple_path_print(table, ROW, COL); getchar(); return 0; } int collect_apple_path_print(int M[ROW][COL], int m, int n) { int i = 1; int j = 1; while (1) { printf("M[%d][%d]=%d\n", i-1, j-1, M[i-1][j-1]); if ((i == m)&&(j == n)) { break; } if (d[i+1][j] >= d[i][j+1]) { i = i + 1; } else { j = j + 1; } } return 0; }
带备忘录的递归算法也可以是一种动态规划算法,这个在《算法的乐趣》中有提到,也是一种非常方便直观的方法。
/** 有1,3,5三种面值的硬币,请问为了得到价值为11,最少需要多少枚硬币。 */ int coins[] = {1, 3, 5}; int memo_cnt[MAX_SUM_VALUE] = {0}; int f_count = 0; int dp_min_coin_count(int value) { f_count++; int min_count = 0; int i = 0; int min = 0xfff; if (value == 0) { return 0; } if (memo_cnt[value] != 0) { return memo_cnt[value]; } for (i = 0; i < sizeof(coins)/sizeof(coins[0]); i++) { if (value >= coins[i]) { int s_value = value - coins[i]; int s_min = dp_min_coin_count(s_value); if (s_min < min) { min = s_min; } } } min_count = min + 1; memo_cnt[value] = min_count; return min_count; } int dp_min_coin_count_demo() { int min_count = 0; int i = 0; for (i = 1; i <= 11; i++) { min_count = dp_min_coin_count(i); printf("min coin count:%d of value:%d enter func count:%d\n", min_count, i, f_count); } return min_count; }
参考:
1.《算法的乐趣》
2. http://www.hawstein.com/posts/dp-novice-to-advanced.html
相关文章推荐
- CSS实现鼠标放图片上显示白色边框+文字描述
- Dijkstra算法java实现
- 第十三周项目3--立体类族共有的抽象类
- 查询mac地址所属厂家的网站
- 你喜欢使用eclipse+tomcat编程吗?!
- 在测试任何应用之前应该了解的20个软件测试小窍门
- GRE写作诀窍:提高运用和表达能力
- Linux定时器
- android内存泄露优化总结
- 自己动手写C语言库函数(6) atoi
- MERGE 更新表数据
- 自定义属性
- 承志医疗管理系统技术解析设置商品折扣率(九)
- mysql的innodb中事务日志ib_logfile
- 51 nod 1007 正整数分组 (简单01背包) && csu 1547: Rectangle
- SAT数学题练习两道
- grub rescue~
- 浅析软件测试用例的优先级
- 没有钱
- Java传参带...的使用方式