凝聚/合并数字组合的算法

时间:2012-06-05 04:29:06

标签: algorithm combinations

使用赛马投注方案,假设我有多个单独的投注来预测比赛的前4名选手(superfecta)。

投注如下......

1/2/3/4  
1/2/3/5  
1/2/4/3  
1/2/4/5  
1/2/5/3  
1/2/5/4 

我想要做的是尽可能地组合或浓缩这些单独的组合。对于上面的赌注,它们可以全部压缩成一行......

1/2/3,4,5/3,4,5

但如果我从名单中删除了最后一个赌注:1/2/5/4 ......

1/2/3/4  
1/2/3/5  
1/2/4/3  
1/2/4/5  
1/2/5/3  

压缩的赌注现在必须是2行:

1/2/3,4/3,4,5  
1/2/5/3  

算法会是什么样的?

2 个答案:

答案 0 :(得分:2)

我发现用漂亮的照片来思考这种事情是最容易的。我们试着建立一些图表怎么样?

第一个例子

1/2/3/4  
1/2/3/5  
1/2/4/3  
1/2/4/5  
1/2/5/3  
1/2/5/4 

...可能会以图表形式显示:

example 1 before

从上到下的每条路径(例如1->2->4->3)对应于初始格式的一行。

如果我们从该图开始,那么(也许)我们可以在图上运行一些算法,以便按照您正在寻找的方式简化它。以下是我们将尝试的内容:

  • 从图表的顶部开始,逐级向下移动。 (第一级仅包含蓝色节点1。)
  • 对于当前级别中的每个节点,计算子级数。如果只有一个孩子,请跳过该节点。 (由于蓝色节点1只有一个孩子,我们将跳到绿色节点2。)
  • 对于多个孩子中的每一个,构建一个包含该孩子及其孙子的集合。 (红色节点3有一组{3,4,5},红色4有一组{3,4,5},而红色5有一组{3,4,5}。)
  • 如果这些集合中的任何一个相同,将相关的子/孙子项替换为包含子项的单个节点,指向包含该集合的孙子。 (由于所有三个红色节点都具有相同的集合,因此它们都将被替换。)

example 1 after


第二个例子

1/2/3/4  
1/2/3/5  
1/2/4/3  
1/2/4/5  
1/2/5/3 

...可能会以图表形式显示:

example 2 before

红色节点34具有相同的集合(即{3,4,5}),因此它们会被替换。红色节点5与红色节点34的设置不同,所以我们不管它。

example 2 after

和以前一样,通过简化树的每条路径代表输出的一行。

(我还没有说明如果你有曾孙子后代替孩子/孙子会发生什么。可能你应该从最底层开始向上工作。)

答案 1 :(得分:0)

通过F#

open System
open System.Collections.Generic

let data =
  [|
    "1/2/3/4"
    "1/2/3/5"
    "1/2/4/3"
    "1/2/4/5"
    "1/2/5/3"
    "1/2/5/4"
  |]
let conv (xs:string []) =
  let xs = xs |> Array.map (fun x -> x.Split('/'))
  let len = xs.[0] |> Array.length
  let sa = Array.init len (fun _ -> new SortedSet<string>())
  xs |> Array.iter (fun xa -> xa |> Array.iteri (fun i x -> sa.[i].Add(x) |>ignore))
  String.Join("/", sa |> Array.map (fun x -> if Seq.length x = 1 then Seq.head x else String.Join(",", x |> Seq.toArray)))

let _ = 
  conv data |> printfn "%s"
//result:1/2/3,4,5/3,4,5

  //use 0-3 and 4 element of data
  [|data.[0..3]; data.[4..4] |]
  |> Array.map (fun x -> conv x)
  |> Array.iter (printfn "%s")
(* result:
1/2/3,4/3,4,5
1/2/5/3
*)