区间型动态规划:合并石子
状态转移方程:
显而易见,这种方法时间复杂度是O(n^3)
,如何去优化?
四边形不等式
通过四边形不等式的优化,可以进一步限定k的范围,从而可以将事件复杂度降为
O(n^2)
,我们最终的目的是证明决策变量k的单调性。
通过不断的搜索,发现此优化方法原来是姚期智的夫人储枫(Frances Yao)所写,默默
膜拜了一番。
算法相关论文地址:论文
价值函数c[i,j]
公式1:
满足公式1,说明价值函数c[i,j]
满足区间的单调性。
公式2:
满足公式2,说明价值函数c[i,j]
满足四边形不等式。
对于石子合并问题,价值函数显然满足上述两个公式。
状态转移函数m[i,j]
要证明状态转移函数也满足四变形不等式.
引理1:
具体的证明过程是通过数学归纳法来的,相关证明过程可参看论文,本人愚顿,看了
好久,才感觉明白了,最重要的一步则是:
证明的过程中又引用了需要证明的结论,我的理解是数学归纳法,上述公式的范围
比结论的范围小,故可以引用。
决策变量的单调性
假设k[i,j]
表示m[i,j]
取得最小值时的决策值。
引理2:
根据对称性只需证明k[i,j-1]<=k[i,j]
, 假设x=k[i,j-1]
,对任意i<y<x<j-1<j
.
不等式两侧同时加上:
then:
因为:
所以:
从而可以确定k[i,j]
不可能小于x,也就是说k[i,j-1]<=k[i,j]
.
石子合并代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include <stdio.h> #include <stdlib.h> #include <string.h> #include <limits.h>
int piles[5001];
int *status[5001]; int *cv[5001];
void quard_dp(){ int n, i, j, k, dis; int min ,tmp; scanf("%d", &n); piles[0] = 0; while(n != 0) { for(i = 1; i <= n; i++){ scanf("%d", &piles[i]); piles[i] += piles[i-1]; status[i] = (int*)malloc((n+1) * sizeof(int)); status[i][i] = 0; cv[i] = (int*)malloc((n+1) * sizeof(int)); cv[i][i] = i; }
for(dis = 1; dis < n; ++dis){ for(i = 1; i <= n-dis; i++){ j = i + dis; min = INT_MAX; for(k = cv[i][j-1]; k <= cv[i+1][j] && k < n; ++k){ tmp = status[i][k] + status[k+1][j] + piles[j]- piles[i-1]; if(tmp < min) { min = tmp; cv[i][j] = k; } } status[i][j] = min; } } printf("%d\n", status[1][n]); for(i = 0; i < n; i++){ free(status[i]); free(cv[i]); }
scanf("%d", &n); } }
|