计算序列数

时间:2017-07-23 09:48:10

标签: algorithm combinatorics

我看到了以下无法解决的问题。什么样的算法会解决它?

我们得到了一个正整数n。设A是长度为n的所有可能字符串的集合,其中字符来自集合{1,2,3,4,5,6},即掷骰子n次的结果。 A的多少个元素包含以下字符串中的至少一个作为子字符串:

1, 2, 3, 4, 5, 6
1, 1, 2, 2, 3, 3
4, 4, 5, 5, 6, 6
1, 1, 1, 2, 2, 2
3, 3, 3, 4, 4, 4
5, 5, 5, 6, 6, 6
1, 1, 1, 1, 1, 1
2, 2, 2, 2, 2, 2
3, 3, 3, 3, 3, 3
4, 4, 4, 4, 4, 4
5, 5, 5, 5, 5, 5
6, 6, 6, 6, 6, 6

我想知道某种递归方法,但当我试图解决问题时,我只是弄得一团糟。

2 个答案:

答案 0 :(得分:1)

我建议您阅读Aho-Corasick algorithm。这基于一组字符串构造有限状态机。 (如果你的字符串列表是固定的,你甚至可以手工完成。)

一旦你有一个有限状态机(大约有70个状态),你应该添加一个额外的吸收状态来标记何时检测到任何字符串。

现在你的问题被减少到找到6 ** n个字符串中有多少在被推进状态机后最终处于吸收状态。

您可以通过将状态机表示为矩阵来完成此操作。条目M [i,j]表示当添加一个字母时从状态j到达状态i的方式的数量。

最后,计算应用于输入向量的幂n的矩阵,除了对应于初始状态的位置中的1之外,该输入向量全为零。吸收状态位置的数字将告诉您字符串的总数。

(您可以使用标准matrix exponentiation algorithm在O(登录)时间内生成此答案。)

答案 1 :(得分:0)

你的递归方法出了什么问题,你能详细说明一下,无论如何这可以用O(6 ^ n)中的递归方法解决,但是可以使用dp进行优化,使用你只需要跟踪的事实最后6个元素,所以它可以用O(6 * 2 ^ 6 * n)和dp完成。

// ===== OPTION 1 =====
// Pattern matching separated out, lazy eval.
let Foo x =
  let valueOne = lazy //... lots of code, evaluated on Force().
  let valueTwo = lazy //... lots of code, evaluated on Force().

  match x with
  | 1 -> valueOne.Force()
  | 2 -> valueTwo.Force()

// ===== OPTION 2 =====
// Pattern matching separated out, with arguments.
let Foo x =
  let valueOne a = //... lots of code.
  let valueTwo a = //... lots of code.

  match x with
  | 1 -> valueOne x
  | 2 -> valueTwo x

// ===== OPTION 3 =====
// Active Pattern matching separated out, with arguments.
let Foo x = 
  let (|ValueOne|_|) inp =
    if inp = 1 then Some(...) else None

  let (|ValueTwo|_|) inp =
    if inp = 2 then Some(...) else None

  match x with
  | ValueOne a -> a
  | ValueTwo b -> b