繁体   English   中英

如何从数字子序列中恢复数字?

[英]How to recover a number from digit subsequences?

给定四位数1234,有六个可能的两位数子序列(12,13,14,23,24,34)。 鉴于一些子序列,是否有可能恢复原始数字?

这是一些示例数据。 每行列出了不同6位数字的三个3位数子序列(待定)

528, 508, 028, 502, 058, 528, 028, 528, 552, 050
163, 635, 635, 130, 163, 633, 130, 330, 635, 135
445, 444, 444, 444, 454, 444, 445, 
011, 350, 601, 651, 601, 511, 511, 360, 601, 351
102, 021, 102, 221, 102, 100, 002, 021, 021, 121
332, 111, 313, 311, 132, 113, 132, 111, 112
362, 650, 230, 172, 120, 165, 372, 202, 702
103, 038, 138, 150, 110, 518, 510, 538, 108
343, 231, 431, 341, 203, 203, 401, 303, 031, 233

编辑:有时候解决方案可能不是唯一的(多个数字可以给出子序列)。 在这种情况下,最好返回其中一个,甚至是一个列表。

你想要做的是找到你所有子序列的最短常见超序 显然,如果您有所有子序列,包括原始编号,SCS将是您正在寻找的。 否则无法保证,但有很好的机会。

不幸的是,对于这个问题没有一个很好的多项式算法,但是如果你谷歌它你会发现有很多可用的近似算法。 例如,针对最短共同超常问题的ACO算法提到了三种总体方法:

  1. 动态编程或Branch'n'Bound。 除了极少数字符串或小字母外,这些通常都会变慢。

  2. 使用动态编程成对地查找字符串的SCS,使用启发式方法选择要“合并”的字符串。

  3. 多数合并启发式可能是最适合您的案例。

  4. 本文描述的方法。

这是另一篇关于这个问题的好文章: http//www.update.uu.se/~shikaree/Westling/

构建一个有向图,每个数字连接到每个序列中跟随它的数字。

处理周期:

一个循环意味着一个不可能的场景 - 同一个角色不能有2个位置(可能有多个位置具有相同值的角色,但不是完全相同的角色 - 作为一个比喻,你可以让很多人命名为Bob,但任何给定的Bob只能在一个地方)。 某些节点必须拆分为多个节点。 应该对所选节点进行拆分,使得所有传入边缘都位于其中一个新节点中,所有传出边缘位于另一个节点中,并且两者之间存在连接。

应该有多个节点可以被挑选进行拆分,可能只有一个是正确的,您可能需要探索所有可能性,直到找到有效的节点。 如果一个不起作用,你将得到一个比在某个地方允许的更长的字符串。

在拓扑排序之前完全摆脱循环可能是一个更好的想法(以相同的方式解决它们)。

处理具有相同值的节点(作为循环解析的结果):

如果有多个节点具有可以选择的相同值,则让出局边缘从第一个节点(具有定向路径的节点到所有其他节点)和传入边缘到最后一个(所有其他节点)有一个有向的路径)。 如果在同一序列中存在多个具有相同值的数字,则显然需要稍微修改。

找到实际的字符串:

要确定字符串,请在图表上进行拓扑排序

例:

假设我们正在寻找一个5位数的数字,输入是:

528, 508, 028, 502, 058, 058

我知道058的重复有些微不足道,但它只是为了说明。

528 ,用于创建节点528 ,并连接5228

5 -> 2 -> 8

对于508 ,创建0 ,连接50以及08

5 -> 2 -> 8
  \    /
   > 0

对于028 ,连接02

5 ------> 2 -> 8
  \    /    /
   > 0 -----

对于502 ,所有连接都已存在。

对于058 ,我们得到一个周期( 5->0->5 ),所以我们有两个选择:

  • 0拆分为2个节点:

      /-----------\\----\\ / vv 0 -> 5 ------> 2 -> 8 \\ > 0 
  • 5分为2个节点:

      /-----------\\ / v 5 ------> 2 -> 5 -> 8 \\ ^ ^ \\ / / > 0 -------- 

让我们假设我们选择后者。

对于058 ,我们需要从最后5 (在这种情况下为右5 )和前5 (在这种情况下为左5 )的传入边缘的传出边缘。 这些边( 5->05->8 )已经存在,所以无所事事。

拓扑排序将给我们50258 ,这是我们的数字。

让逻辑编程为您完成工作。

这是通过 core.logic

定义作为子序列的含义

(defne subseqo [s1 s2] 
  ([(h . t1) (h . t2)] (subseqo t1 t2)) 
  ([(h1 . t1) (h2 . t2)] (!= h1 h2) (subseqo s1 t2)) 
  ([() _]))

通过解算器运行约束。

(defn recover6 [input-string] 
  (run* [q] 
    (fresh [a b c d e f] 
      (== q [a b c d e f]) 
      (everyg (fn [s] (subseqo (seq s) q)) 
              (re-seq #"\d+" input-string)))))

示例(结果在REPL上感知瞬间):

(recover6 "528, 508, 028, 502, 058, 528, 028, 528, 552, 050")
;=> ([\5 \0 \5 \2 \8 \0]
     [\5 \0 \5 \2 \0 \8]
     [\5 \0 \5 \0 \2 \8]
     [\0 \5 \0 \5 \2 \8]
     [\0 \5 \5 \0 \2 \8])

(recover6 "163, 635, 635, 130, 163, 633, 130, 330, 635, 135")
;=> ([\1 \6 \3 \5 \3 \0] 
     [\1 \6 \3 \3 \5 \0] 
     [\1 \6 \3 \3 \0 \5])

(recover6 "445, 444, 444, 444, 454, 444, 445")
;=> ([\4 \4 \5 \4 _0 _1] 
     ... and many more

在最后一个示例中,下划线表示_0_1是自由变量。 他们没有受到限制。 将任何自由变量约束到数字集很容易。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM