先看三则算法的代码:
0-1 背包问题:
int dpf[N+1][W+1]; //数组从0开始 int dp_solve() { for(int i=0; i<N;i++) for(int j=0; j<=W;j++) if(j<w[i]) dpf[i+1][j]=dpf[i][j]; else dpf[i+1][j]=max(dpf[i][j],dpf[i][j-w[i]]+v[i]); return dpf[N][W]; }
int dp[N+1][W+1]; //数组从0开始 int dpsolve() { for(int i=0; i<N;i++) for(int j=0; j<=W;j++) if(j<w[i]) dp[i+1][j]=dp[i][j]; else dp[i+1][j]=max(dp[i][j],dp[i+1][j-w[i]]+v[i]); return dpf[N][W]; }
int dp[m+1][n+1]; int Lcs() { for(int i=0;i<m;i++) for(int j=0;j<n;j++) if(s1[i]==s2[j]) dp[i+1][j+1]= dp[i][j]+1; else dp[i+1][j+1]= max(dp[i+1][j],dp[i][j+1]); return dp[m][n]; }
0-1 背包问题 (一维数组DP):
int dp[W+1]; //数组从0开始 int dp_solve() { for(int i=0; i<N;i++) for(int j=W; j>=w[i];j--) dp[j] = max( dp[j], dp[j-w[i]]+v[i]); return dp[W]; }
完全背包问题(一维数组DP):
int dp[W+1]; //数组从0开始 int dp_solve() { for(int i=0; i<N;i++) for(int j=w[i]; j<=W;j++) dp[j] = max( dp[j], dp[j-w[i]]+v[i]); return dp[W]; }
而对于LCS,我们无能为力,分析其原因,可以发现,当 DP算法当前的状态 dp[i+1][j+1] 和 dp[i][j] , dp[i-p][j-q] 等值相关时,如下图所示D 为当前状态,C代表同行前置状态,B代表同列上层状态, A 代表D的上层并且前置状态 。
设 D = max { fun(A), fun(B), fun(C) }
(1) 当 D = max { fun(A), fun(B) } 即D仅和 A 、B 相关,可以使用一维数组优化,其二级循环 为 从大到小,(因为要使用到 上一层A 状态相关,从小到大 会更新A 的状态),如下代码:
for(int i=0; i<N;i++) for(int j=M; j>=0;j--) // loop codes
(2) 当 D = max { fun(B), fun(C) } 即D 仅和 B、C相关,可以使用一维数组优化,其二级循环为从小到大,(因为要使用本层状态C的最新值,所以需要先更新C,再考虑D),如下代码:
for(int i=0; i<N;i++) for(int j=M; j>=0;j--) // loop codes
(3) D = max { fun(A), fun(C) } 即 D 和 A、C 存在关联时,不可以使用一维数组优化,因为 D 和 A 相关,那么要求 二级循环从大到小,而D和C相关,却要求二级循环从小到大。矛盾,所以不可行。
当我们遇到一维数组无法优化 二级 DP 内存消耗时,我们也可以用一个绝对靠谱的方法,也就是交替法,使用两个一维数组搞定(如 dp[2][M]).
【大家明白才是真的明白】动态规划算法什么时候能用一维数组解问题,布布扣,bubuko.com
【大家明白才是真的明白】动态规划算法什么时候能用一维数组解问题
原文:http://blog.csdn.net/tbwood/article/details/22747215