所以有 2^N 选择,因为在每一点你要么从 A 中选择,要么从 B 中选择。在具体的例子中,你给出的 N 恰好是 3,有 8 个。为了讨论,你可以将每组决策描述为一个位模式。
因此,蛮力方法会尝试每一个位模式。
但是应该很明显的是,如果前几位产生的数字太大,那么每个后续可能的尾位组也会产生一个太大的数字。因此,建模它的更好方法可能是一棵树,您不必费心沿着已经长出极限的四肢走下去。
您还可以计算从每个位到表末尾可以达到的最大总数。如果在任何时候你的运行总数加上你可以从这里获得的最大值小于 K,那么你所在的每个子树都是可以接受的,不需要遍历。正如评论中所讨论的那样,每个组合都是可以接受的,这是这种观察的一个特例。
正如下面 Serge 所指出的,对我们来说,一个相关的观察是最小值并使用相反的逻辑来取消整个子树而无需遍历。
一个潜在的进一步优化基于这样的观察,只要我们以相同的方式洗牌,改变 A 和 B 的顺序就没有效果,因为加法是可交换的。因此,您可以努力确保最大值尽可能快地增长或最小值尽可能慢地增长,以尝试尽早退出遍历。在实践中,您可能希望应用启发式方法将绝对最大值和最小值(无论如何您都已经计算过)与 K 进行比较。
在这种情况下,递归实现是最简单的,例如(在 C 中)
/* assume A, B and N are known globals */
unsigned int numberOfGoodArraysFromBit(
unsigned int bit,
unsigned int runningTotal,
unsigned int limit)
{
// have we ended up in an unacceptable subtree?
if(runningTotal > limit) return 0;
// have we reached the leaf node without at any
// point finding this subtree to be unacceptable?
if(bit >= N) return 1;
// maybe every subtree is acceptable?
if(runningTotal + MAXV[bit] <= limit)
{
return 1 << (N - bit);
}
// maybe no subtrees are acceptable?
if(runningTotal + MINV[bit] > limit)
{
return 0;
}
// if we can't prima facie judge the subtreees,
// we'll need specifically to evaluate them
return
numberOfGoodArraysFromBit(bit+1, runningTotal+A[bit], limit) +
numberOfGoodArraysFromBit(bit+1, runningTotal+B[bit], limit);
}
// work out the minimum and maximum values at each position
for(int i = 0; i < N; i++)
{
MAXV[i] = MAX(A[i], B[i]);
MINV[i] = MIN(A[i], B[i]);
}
// hence work out the cumulative totals from right to left
for(int i = N-2; i >= 0; i--)
{
MAXV[i] += MAXV[i+1];
MINV[i] += MINV[i+1];
}
// to kick it off
printf("Total valid combinations is %u", numberOfGoodArraysFromBit(0, 0, K));
我只是即兴思考;可能存在更好的解决方案。