Math 找出不同的写作方式的数量';1';作为分数的总和,每个分数都带有';1';作为分子和'的幂;2';作为分母

Math 找出不同的写作方式的数量';1';作为分数的总和,每个分数都带有';1';作为分子和'的幂;2';作为分母,math,dynamic-programming,integer-arithmetic,Math,Dynamic Programming,Integer Arithmetic,我得到一个数字n,我必须找到不同的方法的数量,将数字1作为n分数的总和,其中每个分数具有以下格式: 分子总是1 分母是2的幂(例如2^1、2^2等) 两种将1写成此类分数总和的方法,如果它们包含相同的分数,则不存在差异。例如,假设n=4。将1写成4分数总和的一种方法是:1/2+1/4+1/8+1/8。但是将其写成1/8+1/4+1/2+1/8被认为是相同的(因为它包含完全相同的分数,只是顺序发生了变化),因此与第一种书写方式相比没有区别。因此,对于n=4而言,只有两种方法可以将1写成4个分数

我得到一个数字
n
,我必须找到不同的方法的数量,将数字
1
作为
n
分数的总和,其中每个分数具有以下格式:

  • 分子总是1
  • 分母是2的幂(例如2^1、2^2等)

两种将
1
写成此类分数总和的方法,如果它们包含相同的分数,则不存在差异。例如,假设
n=4
。将
1
写成
4
分数总和的一种方法是:
1/2+1/4+1/8+1/8
。但是将其写成
1/8+1/4+1/2+1/8
被认为是相同的(因为它包含完全相同的分数,只是顺序发生了变化),因此与第一种书写方式相比没有区别。因此,对于
n=4
而言,只有两种方法可以将
1
写成4个分数的总和。第一个是
1/2+1/4+1/8+1/8
(上面提到的那个),第二个是
1/4+1/4+1/4+1/4
。因此结果将是
2
n
的边界是:
2我建议你从玩几轮游戏开始。但如果你停不下来,别怪我

你的总和列表有一个最小的2−K你可以将你的总和按2k的比例缩放,使所有的数字都成为整数,实际上是二的幂。这可能会使思考这个问题变得更容易。现在把求和看作是对二进制数的一种运算,例如

   0100
   0100
   0100
   0010
   0001
+  0001
= 10000
开始添加最低的整数。肯定有两个。否则你就不能把最后一点归零。如果n=1,则为该规则的例外情况,即您只有一个和。所以你可以把两个最小的数字相加,得到一个两倍大的数字。然后继续,直到达到一个数字。如果需要,可以对二进制分数执行相同的操作,以避免缩放步骤

所以这里一个重要的不变量是,你可以用这样一种方式添加项,它们仍然是2的负幂。添加的序列将形成一个二叉树,节点的值由深度表示:根有1,下一级有1/2,下一级有1/4,依此类推。每个节点要么是一个具有零个子节点的叶节点,要么是一个具有两个子节点的内部节点。你感兴趣的是具有N叶的二叉树,但是如果树在每个级别上都有相同数量的叶子,则认为它们是相等的。 要开始递归思考,如何从一棵有n片叶子的树变成一棵有n+1片叶子的树?将一对子项添加到现有叶中。让我们编写一些python代码

def扩展(v): 对于范围内的i(透镜(v)-1): 如果v[i]: 产出元组(如果j==i else x,则x-1+2如果j==i+1 else x 对于枚举(v)中的j,x) 产量v[:-1]+(v[-1]-1,2)#开始一个新的水平 s=set([(1,))#从裸根开始 对于范围(1,21)内的n: 打印({:4d}:{:10d})。格式(n,len(s))) s=集合(y代表x,s代表y代表展开式(x))
然后,进入并输入您辛苦获得的序列。搜索将列出一个命中,描述为

1到n次方1/2的分区数

宾果。不幸的是,它没有一个封闭的公式。但是有一个为n=2000预先计算的值列表。下面是一个shell脚本,通过查找以下内容来确定任意给定n的结果:

wget-qO-'http://oeis.org/A002572/b002572.txt“|尾-n+${n:?}|头-n1 |切-d”'-f2
如果你想要一个更严肃的答案,我建议你遵循OEIS上引用的参考资料。或者试着理解一下函数
v
,它被描述为

v(c,d)是将d划分为形式为d=c+c1+c2+…+cn的正整数的数目,其中c1≤ 2. c、 ci+1≤ 2. ci

用于Mathematica、Maple和Pari中的一些神奇的动态规划

那么连接在哪里呢?要回答这个问题,请从考虑叶节点切换到考虑内部节点。如果有n个叶节点,那么就有d=n−1内部节点。v(1,d)是通过按层划分内部节点的数量来计算排列这些内部节点的方式。您需要在根节点上有一个内部节点,除非您的n=1没有被考虑在内。每个后续层至少可以有零个内部节点,最多是前一层内部节点数量的两倍

除了角点情况,基本递归是

v(c, d) = sum(v(i, d-c) for i=1..2*c)
因为如果d=c+c1+c2+…+cm,那么这对应于d−c=c1+c2+…+cm,因此需要对
d-c
进行分区,其中
i
=c1介于0和2之间 C这可以用于一个很好的动态编程实现。以下是计算d=20,即n=21时所需的所有值:


“我觉得我必须使用动态编程”-为什么?还有,你到底试过什么?我看不到code@Fureeish我已经说过我试着用斐波那契序列从序列中提取答案,但结果证明是错误的。发布错误的代码有什么意义?除此之外,我没有尝试过其他方法,因为我不知道如何解决这个问题。我需要一个主意。这就是为什么我问这个问题。“发布错误的代码有什么意义?”-这样我们可以帮助您检查代码的错误。粘贴您的代码,解释思考过程,然后我们将能够看到您在实现中可能出现的错误。当然,除非你证明你的算法和整个想法是错误的。更重要的是,堆栈溢出不是一个人们会为您找出算法的地方。这是一个特定编程问题的地方。这里没有“关于如何开始解决这个问题的任何想法”之类的问题。
v(c,d)   c=1   c=2   c=3   c=4   c=5   c=6   c=7   c=8   c=9
 d= 1:     1
 d= 2:     1     1
 d= 3:     2     1     1
 d= 4:     3     2     1     1
 d= 5:     5     4     2     1     1
 d= 6:     9     7     4     2     1     1
 d= 7:    16    12     7     4     2     1     1
 d= 8:    28    22    13     7     4     2     1     1
 d= 9:    50    39    24    13     7     4     2     1     1
 d=10:    89    70    42    24    13     7     4     2
 d=11:   159   126    76    43    24    13     7     4
 d=12:   285   225   137    78    43    24    13     7
 d=13:   510   404   245   140    78    43    24    13
 d=14:   914   725   441   251   141    78
 d=15:  1639  1299   792   452
 d=16:  2938  2331  1420   812
 d=17:  5269  4182  2550  1457
 d=18:  9451  7501
 d=19: 16952 13458
 d=20: 30410