编辑:不知何故,我查看了问题中的“寻找最短路径”短语,而忽略了原始问题后来澄清意图的“长度”短语。因此,我在下面的两个答案都存储了大量额外的数据,以便在计算出它的长度后轻松回溯正确的路径。如果您在计算长度后不需要回溯,我的原始版本可以将其第一个维度从 N 更改为 2,并且只存储一个奇数 J 和一个偶数 J,覆盖任何旧的。我更快的版本可以降低管理 J、R 交互的所有复杂性,并且只需将其外部级别存储为 [0..1][0..H] 这些都不会改变时间,但它会改变存储空间。
要理解我的答案,首先要了解一个粗略的 N^3 答案:(我不知道我的实际答案是否比粗略的 N^3 具有更好的最坏情况,但它具有更好的平均情况)。
注意N必须是奇数,表示为N=2H+1。 (P 也必须是奇数。如果给定偶数 P,则减少 P。但如果 N 是偶数,则拒绝输入。)
使用 3 个真实坐标和 1 个隐含坐标存储成本:
J = 列 0 到 N
R = 红色边数 0 到 H
B = 黑边计数 0 到 P
S = 奇数或偶数(S 只是 B%1)
我们将计算/存储成本[J][R][B] 作为使用恰好 R 个红色边缘和恰好 B 个黑色边缘到达 J 列的最低成本方式。 (我们也使用了 J-R 蓝色边缘,但这是多余的)。
为方便起见,直接写入cost,但通过访问器c(j,r,b) 读取它,当r<0 || b<0 时返回BIG,否则返回cost[j][r][b]。
那么最里面的一步就是:
If (S)
cost[J+1][R][B] = red[J]+min( c(J,R-1,B), c(J,R-1,B-1)+black[J] );
else
cost[J+1][R][B] = blue[J]+min( c(J,R,B), c(J,R,B-1)+black[J] );
将 cost[0][0][0] 初始化为零,对于超粗版本,将所有其他 cost[0][R][B] 初始化为 BIG。
您可以超级粗略地循环增加 J 序列以及您喜欢计算所有这些的任何 R、B 序列。
最后,我们可以找到答案:
min( min(cost[N][H][all odd]), black[N]+min(cost[N][H][all even]) )
但一半的 R 值并不是问题的一部分。在前半部分,任何R>J 都是不可能的,而在后半部分,任何R<J+H-N 都是无用的。您可以轻松避免计算这些。使用更智能的访问器函数,您可以避免在需要计算的边界情况下使用从未计算过的位置。
如果任何新成本[J][R][B] 不小于相同 J、R 和 S 的成本但低于 B,则该新成本是无用数据。如果结构的最后一个暗点是映射而不是数组,我们可以轻松地计算一个从存储空间和时间中删除无用数据的序列。但是,减少的时间会乘以这些地图的平均大小(最大为 P)的对数。所以在一般情况下可能会赢,但在最坏的情况下可能会输。
稍微考虑一下成本所需的数据类型和 BIG 所需的值。如果该数据类型中的某个精确值既与最长路径一样大,又小至可以存储在该数据类型中的最大值的一半,那么对于 BIG 来说这是一个微不足道的选择。否则,您需要更谨慎地选择以避免任何舍入或截断。
如果您遵循所有这些,您可能会理解我认为难以解释的更好方法之一:这将使元素大小增加一倍,但将元素数量减少到一半以下。它将获得 std::map 调整到基本设计的所有好处,而无需 log(P) 成本。它将在不影响病理病例时间的情况下缩短平均时间。
定义一个包含成本和黑色计数的结构 CB。主存储是vector<vector<CB>>。对于每个有效的 J,R 组合,外部向量都有一个位置。这些是常规模式,因此我们可以轻松计算给定 J,R 或给定位置的 J,R 在向量中的位置。但是以增量方式保留它们会更快,因此 J 和 R 是隐含的,而不是直接使用的。向量应保留为其最终大小,约为 N^2/4。最好预先计算H,0 的索引
每个内部向量都有严格递增的B序列和中的C,B对,严格递减的C序列。一次生成一个内部向量(在临时向量中),然后复制到它们的最终位置,然后只读取(不修改)。在每个内部向量的生成中,候选 C,B 对将按递增的 B 序列生成。所以在构建临时向量时保持 bestOdd 和 bestEven 的位置。然后,只有当每个候选者的 C 低于最佳(或最佳尚不存在)时,才会将每个候选者推入向量中。我们还可以将所有 B<P+J-N 视为 B==S,因此该范围内的较低 C 替换而不是推送。
外向量的隐含(从未存储)J,R 对以 (0,0) (1,0) (1,1) (2,0) 开始,以 (N-1,H-1) 结束) (N-1,H) (N,H)。以增量方式处理这些索引是最快的,所以当我们计算隐含位置 J,R 的向量时,我们将 V 作为 J,R 的实际位置,U 作为 J-1 的实际位置,R 和 minU 作为 J-1 的第一个位置,?和 minV 作为 J 的第一个位置,?和 minW 作为 J+1 的第一个位置,?
在外循环中,我们简单地将 minV 复制到 minU 并将 minW 复制到 minV 和 V,并且很容易计算新的 minW 并确定 U 是从 minU 还是 minU+1 开始。
内部的循环将 V 推进到(但不包括)minW,而每次推进 V 时推进 U,并且在典型位置使用位置 U-1 处的向量和位置 U 处的向量一起计算向量对于位置 V。但是您必须涵盖不使用 U-1 处的向量的 U==minU 的特殊情况和仅使用 U-1 处的向量的 U==minV 的特殊情况。
当组合两个向量时,您可以通过 B 值同步遍历它们,使用一个或另一个根据遇到的 B 值生成候选者(见上文)。
概念:假设您了解如何存储具有隐含 J,R 和显式 C,B 的值:其含义是存在一条以成本 C 使用恰好 R 个红色分支和恰好 B 个黑色分支的列 J 的路径 并且不存在到列 J 的路径,该路径使用恰好 R 个红色分支和相同的 S,其中 C' 或 B' 中的一个更好,另一个不差。