C++ 降低阵列最大最小和2-划分的时间复杂度
让C++ 降低阵列最大最小和2-划分的时间复杂度,c++,algorithm,recursion,dynamic-programming,C++,Algorithm,Recursion,Dynamic Programming,让array[N]一个N非负值数组。我们试图递归地将数组划分为两(2)个子数组,这样我们就可以实现每个子数组的最大“最小和”。解决方案由以下递归描述: 我们要计算opt[0][N-1] 让c[x][y]表示从x到y的sum{array[i]}(包括)。 我已经成功地使用下面的C++程序片段解开递归,使用动态编程: for ( uint16_t K1 = 0; K1 < N; K1 ++ ) { for ( uint16_t K2 = 0; K2 < N-K1; K2 ++
array[N]
一个N
非负值数组。我们试图递归地将数组划分为两(2)个子数组,这样我们就可以实现每个子数组的最大“最小和”。解决方案由以下递归描述:
我们要计算opt[0][N-1]
让c[x][y]
表示从x
到y
的sum{array[i]}
(包括)。
我已经成功地使用下面的C++程序片段解开递归,使用动态编程:
for ( uint16_t K1 = 0; K1 < N; K1 ++ ) {
for ( uint16_t K2 = 0; K2 < N-K1; K2 ++ ) {
const uint16_t x = K2, y = K2 + K1;
opt[x][y] = 0;
for ( uint16_t w = x; w < y; w ++ ) {
uint32_t left = c[x][w] + opt[x][w];
uint32_t right = c[w+1][y] + opt[w+1][y];
/* Choose minimum between left-right */
uint32_t val = MIN( left, right );
/* Best opt[x][y] ? */
if ( val > opt[x][y] ) {
opt[x][y] = val;
}
}
} /* K2 */
} /* K1 */
(uint16_t K1=0;K1{
对于(uint16_t K2=0;K2opt[x][y]){
opt[x][y]=val;
}
}
}/*K2*/
}/*K1*/
此技术解析所有子阵列,从大小1
到大小N
。因此,最终溶液将存储在opt[0][N-1]
中
例如,如果N=6
,矩阵将按如下方式迭代:(0,0)(1,1)(2,2)(3,3)(4,4)(5,5)(0,1)(1,2)(2,3)(3,4)(4,5)(0,2)(1,3)(2,4)(3,5)(0,3)(1,4)(2,5)(0,4)(1,5)(0,5)
。最终答案将出现在opt[0][5]
中
我已经测试并验证了上面的技术可以解除递归。我试图进一步降低复杂性,因为如果我是正确的,这将在O(n^3)中运行。这能实现吗
编辑:我还注意到递归的物理意义,正如在评论中所问的那样。让
N
表示跨越直线的N
城市。我们是控制这些城市的地主;在一年的末,每个城市i
只要在我们的控制下,就会支付array[i]
硬币的维护费
我们的城市正受到优势部队的攻击,失败是不可避免的。每年年初,我们在两个相邻的城市之间筑起一堵墙,
i
,i+1
,x以下是问题的最终答案,请参考@NiklasB.。让w(x,y)
表示问题opt[x][y]
的数组的最佳分区。如下所示,x这类似于矩阵乘法中的dp,它在这里不起作用,因为你试图将一个集合分成两个子集合,并且总和尽可能接近相等。我说得对吗?这看起来不像是一个已知的多项式时间解。@n.m如果子集必须是连续的,这并不难,就像在这种情况下。而且复发看起来比以前更复杂that@NiklasB对不起,我没听懂。这与集合划分或子集和问题有何不同?FWIW,让w(x,y)是opt(x,y)定义中的最优w。我猜想在所有情况下都有一个w(x,y+1)>=w(x,y)的解,并且你的递归的右边在w中是凸的。这使您可以通过固定x,然后按递增顺序计算y,从而去除时间复杂度中n的一个因子,得到O(n^2)。作为参考,Donald Knuth讨论了此类优化,后来Yao在
for ( uint16_t w = wall[x][y-1]; w <= wall[x+1][y]; w ++ ) {
...
if ( val > opt[x][y] ) {
opt[x][y] = val;
wall[x][y] = w;
}
}