定义为通过稳定合并和F(i, j)
可以实现的最大成对和。Ai...An
Bj...Bn
在合并的每一步,我们可以选择以下三个选项之一:
- 取 的前两个剩余元素
A
。
- 取 的第一个剩余元素
A
和 的第一个剩余元素B
。
- 取 的前两个剩余元素
B
。
因此,F(i, j)
可以递归定义为:
F(n, n) = 0
F(i, j) = max
(
AiAi+1 + F(i+2, j), //Option 1
AiBj + F(i+1, j+1), //Option 2
BjBj+1 + F(i, j+2) //Option 3
)
为了找到两个列表的最佳合并,我们需要F(0, 0)
天真地找到 ,这将涉及多次计算中间值,但是通过缓存每个F(i, j)
找到的值,复杂性降低到O(n^2)
。
这是一些快速而肮脏的c ++,它可以做到这一点:
#include <iostream>
#define INVALID -1
int max(int p, int q, int r)
{
return p >= q && p >= r ? p : q >= r ? q : r;
}
int F(int i, int j, int * a, int * b, int len, int * cache)
{
if (cache[i * (len + 1) + j] != INVALID)
return cache[i * (len + 1) + j];
int p = 0, q = 0, r = 0;
if (i < len && j < len)
p = a[i] * b[j] + F(i + 1, j + 1, a, b, len, cache);
if (i + 1 < len)
q = a[i] * a[i + 1] + F(i + 2, j, a, b, len, cache);
if (j + 1 < len)
r = b[j] * b[j + 1] + F(i, j + 2, a, b, len, cache);
return cache[i * (len + 1) + j] = max(p, q, r);
}
int main(int argc, char ** argv)
{
int a[] = {2, 1, 3};
int b[] = {3, 7, 9};
int len = 3;
int cache[(len + 1) * (len + 1)];
for (int i = 0; i < (len + 1) * (len + 1); i++)
cache[i] = INVALID;
cache[(len + 1) * (len + 1) - 1] = 0;
std::cout << F(0, 0, a, b, len, cache) << std::endl;
}
如果您需要实际的合并序列而不仅仅是总和,您还必须缓存哪个p, q, r
被选中并回溯。