对于这个问题,首先按照《编程之美》中的分析对这个问题进行一定的简化。从2n个数中找n个元素,有三种可能:大于Sum/2,小于Sum/2以及等于Sum/2。而大于Sum/2与小于等于Sum/2没区别,故可以只考虑小于等于Sum/2的情况。
动态规划第一步,分析子问题:
这里我们用一个三维数组F[][][]表示子问题,F[i][j][k]表示前i个元素中选取j个元素,使得其和不超过k且最接近k。这个子问题可以根据第i个元素是否选择来进行分析:
如果我们想回溯找到一组合理的分割方式,那么在子问题的求解过程中,就要记录有效的路径,这样我们再用一个三维数组path[][][]来记录。
伪代码如下所示:
1 F[][][] = 0 2 path[][][] = 1 3 4 for i = 1 to 2*N 5 nLimit = min(i, N) 6 for j = 1 to nLimit 7 for k = 1 to sum/2 8 F[i][j][k] = F[i-1][j][k] 9 if k > A[i] && F[i-1][j-1][k-A[i]] + A[i] > F[i][j][k] 10 F[i][j][k] = F[i-1][j-1][k-A[i]] + A[i] 11 path[i][j][k] = 1 12 13 return F[2N][N][sum/2], path[][][]