我有一个对称矩阵,如下图所示。
我编写了 AB 符号,表示网格点(A,B)的值。此外,写 ABC 给出我是这样的最小网格点值: MIN((A,B),(A,C),(B,C))。
另一个例子 A.B.D 给了我 MIN((A,B),(A,D),(B,D))。
我的目标是一次找到一行的所有字母组合(不重复)的最小值,例如,对于此示例,我需要找到关于行A的最小值,这些值由计算给出:
A.B = 6
A.C = 8
A.D = 4
A.B.C = MIN(6,8,6)= 6
A.B.D = MIN(6,4,4)= 4
A.C.D = MIN(8,4,2)= 2
A.B.C.D = MIN(6,8,4,6,4,2)= 2
我意识到某些计算可以重复使用,随着矩阵大小的增加变得越来越重要,但问题是找到实现这种重用的最有效方法。
可以指出我正确的方向找到一个有效的算法/数据结构我可以用来解决这个问题吗?
答案 0 :(得分:1)
嗯,这看起来很简单,但也许我误解了这个问题。我会这样做:
让P
成为符号X1.X2. ... .Xn
中的模式字符串,其中Xi
是矩阵中的列
首先计算数组CS = [ (X1, X2), (X1, X3), ... (X1, Xn) ]
,其中包含X1
与模式中每个其他元素的所有组合; CS
有n-1
个元素,您可以在O(n)中轻松构建
现在您必须计算min (CS)
,即找到与CS
中的组合对应的矩阵元素的最小值;再次,您可以轻松找到O(n)
进行。
注意:由于你的矩阵是对称的,给定P
你只需要通过将CS
的第一个元素与所有其他元素相结合来计算P
:(X1, Xi)
是相等的到(Xi, X1)
如果您的矩阵非常大,而您想进行一些优化,可以考虑P
的前缀:让我用一个例子来解释
解决了P = X1.X2.X3
的问题后,将结果存储在关联地图中,其中X1.X2.X3
是关键
稍后,当您解决问题P' = X1.X2.X3.X7.X9.X10.X11
时,您会在地图中搜索P'
的最长前缀:您可以从P'
开始并删除一个组件(Xi
)从结束到您在地图中找到匹配项,或者您最终得到一个空字符串
如果您在地图中找到P'
的前缀,那么您已经知道该问题的解决方案,因此您只需要找到因组合前缀的第一个元素而导致的问题的解决方案使用后缀,然后比较两个结果:在我们的示例中,前缀为X1.X2.X3
,因此您只需要解决问题
X1.X7.X9.X10.X11
,然后比较两个值并选择min(不要忘记使用新模式更新地图P'
)
如果您没有找到任何前缀,那么您必须解决P'
的整个问题(并且再次不要忘记使用结果更新地图,以便您可以在未来)
这种技术本质上是memoization的一种形式。
答案 1 :(得分:1)
你会想到lattice of subsets of the letters, ordered by inclusion。从本质上讲,你给每个大小为2的子集S都有一个值f(S)(也就是说,矩阵的每个非对角线元素 - 对角元素似乎没有出现在你的问题中),问题是找到大小大于2的每个子集T,T中包含的所有S大小为2的最小f(S)(然后你只对包含某个元素“A”的集合T感兴趣 - 但是我们暂时不要理会。)
首先,请注意,如果您有n个字母,则相当于询问Omega(2 ^ n)个问题,每个子集大约有一个问题。 (不包括零元素和单元素子集以及不包含“A”的子集,分别为big Omega保留n + 1组和因子2,因此如果你想要存储所有这些答案即使是中等大小的n,你需要大量的内存。如果应用程序中的n很大,最好存储一些预先计算的数据集合,并在需要特定数据点时进行一些计算;我没有想过哪种方法最有效,但是例如,只有格子中包含的二叉树的计算数据不一定会帮助你预先计算任何东西。
有了这些东西,让我们假设您实际上想要计算并存储在内存中的所有答案。你需要逐层计算这些,也就是说,从三元素子集开始(因为你的矩阵已经给出了两元素子集),然后是四元素,然后是五元素等等。这样,对于给定的子集S,当我们计算f(S)时,我们已经计算了严格包含在S中的T的所有f(T)。有几种方法可以使用它,但我认为最简单的可能就是使用两个这样的子集S:让t1和t2是T的两个不同的元素,你可以根据自己的喜好选择;让S成为删除t1和t2时得到的T的子集。为S加t1写S1,为S加t2写S2。现在T中包含的每对字母都完全包含在S1中,或者完全包含在S2中,或者它是{t1,t2}。在先前计算的值中查找f(S1)和f(S2),然后直接在矩阵中查找f({t1,t2}),并存储f(T)=这3个数中的最小值。
如果您从未为t1或t2选择“A”,那么您确实可以计算您感兴趣的所有内容,而不计算任何不包含“A”的集合T的f。 (这是可能的,因为只要T包含至少三个元素,上面列出的步骤才有意义。)好!这只留下一个问题 - 如何存储计算值f(T)。我要做的是使用2 ^(n-1)大小的数组;表示每个字母表的子集 - 包含 - “A”乘以(n-1)位数,其中第i位是1,只要第(i + 1)个字母在该集合中(所以0010110,其中有2位,4位和5位,表示字母“A”中的子集{“A”,“C”,“D”,“F”}。“H” - 注意我正在计算位开始从右边开始,从“A”开始的字母= 0)。这样,您实际上可以按数字顺序迭代集合,而不需要考虑如何遍历n元素集的所有k元素子集。 (当需要考虑的集合有0或1个元素时,您需要包含一个特殊情况,在这种情况下,您将不想做任何事情,或者2个元素,在这种情况下,您只需从矩阵中复制值。)< / p>