Algorithm 使用边界查找前提数的算法?

Algorithm 使用边界查找前提数的算法?,algorithm,Algorithm,我想知道是否有一种算法可以告诉我,如果我在边界内寻找排列,会得到多少结果 我有一个寻找组合的程序。最好的解释方法是举个例子,假设你有4件东西想在商店买:苹果、桃子、梨和橘子。你想知道每个篮子能装多少百分比,但你告诉自己,你想每个篮子最少装20个,每个篮子最多装60个(所以苹果:25,桃子:25,梨:25,橘子:25效果很好,但苹果:0,桃子:0,梨:50,橘子:50,因为我们把最小值设为25)。如果运行此示例,返回的正确项目数将为1771 有没有办法提前计算而不是运行实际的程序?我有一个程序需要

我想知道是否有一种算法可以告诉我,如果我在边界内寻找排列,会得到多少结果

我有一个寻找组合的程序。最好的解释方法是举个例子,假设你有4件东西想在商店买:苹果、桃子、梨和橘子。你想知道每个篮子能装多少百分比,但你告诉自己,你想每个篮子最少装20个,每个篮子最多装60个(所以苹果:25,桃子:25,梨:25,橘子:25效果很好,但苹果:0,桃子:0,梨:50,橘子:50,因为我们把最小值设为25)。如果运行此示例,返回的正确项目数将为1771

有没有办法提前计算而不是运行实际的程序?我有一个程序需要做预计算,我正试图找到理想的组合,所以我想写一个程序,给我正确的输出,然后我会对输入进行蒙特卡罗模拟,找到我喜欢的项目/范围的组合

这是我使用的程序(在我的情况下,当顶部波段从未使用时,它可以工作,但如果范围是tigher,1-4,则它不工作,因为它给我的组合没有考虑范围):

这给了我正确的答案(1771),因为它不需要考虑最大值(60),因为它从未达到(它只使用20作为输入)。但是,有没有一种方法可以修改这个公式(或者使用其他方法)来告诉我,如果我有40个项目,范围是2-5,或者其他什么东西(也可以考虑最大值),那么预期的结果是多少


有没有一种算法可以满足我的要求

您可以使用包含排除原则找到数字。假设
distributions(itemCount,bucketCount)
itemCount
项到
bucketCount
存储桶的无限制分发数。我忽略了下限,因为这是通过减去
bucketCount*lowerLimit
项来处理的

itemCount
项目分配到
bucketCount
存储桶(每个存储桶最多包含
upperLimit
项目)的方法的数量是无限制分配的数量减去至少一个存储桶包含超过
upperLimit
项目的无限制分配的数量。后者可用包含排除原则计算,如下所示:

  • bucketCount
    选择的存储桶至少包含
    upperLimit+1
    项,还有
    itemCount-(upperLimit+1)
    项要分发到
    bucketCount
    存储桶:

    bucketCount * distributions(itemCount - (upperLimit+1), bucketCount)
    
    必须从无限制分发的数量中减去

  • 但是我们已经减去了两个bucket包含超过
    上限
    项的分布两次,我们必须纠正这一点并加上

    nCr(bucketCount,2) * distributions(itemCount - 2*(upperLimit+1), bucketCount)
    
    同样,因为有两个桶的
    nCr(bucketCount,2)
    选择

  • 但是我们已经减去了三个桶中包含超过
    上限
    项的分布三次,然后再加三次(
    nCr(3,2)
    ),所以我们必须减去

    nCr(bucketCount,3) * distributions(itemCount - 3*(upperLimit+1), bucketCount)
    
    纠正这一点。等等

总而言之,这个数字是

 m
 ∑ (-1)^k * nCr(bucketCount,k) * distributions(itemCount - k*(upperLimit+1), bucketCount)
k=0
在哪里

(因为无法分配负数的项目)

更正了gist中的代码,实现了计算项目分配方式的函数,包括下限和上限:

import math

def nCr(n,r):
    f = math.factorial
    return f(n) / f(r) / f(n-r)

def itemCount_cal(target, items, minValue):
    return target- items*minValue

def distributions(itemCount, bucketCount):
    # There's one way to distribute 0 items to any number of buckets: all get 0 items
    if itemCount == 0:
        return 1
    # we can't distribute fewer than 0 items, and we need at least one bucket
    if itemCount < 0 or bucketCount < 1:
        return 0
    # If there's only one bucket, there's only one way
    if bucketCount == 1:
        return 1
    #get all possible solutions
    # The number of ways to distribute n items to b buckets is
    # nCr(n+b-1,n)
    f = math.factorial
    return f(itemCount + bucketCount-1)/(f(itemCount) *  f(bucketCount-1))

def ways(items,buckets,lower,upper):
    if upper < lower: # upper limit smaller than lower: impossible
        return 0
    if buckets*upper < items: # too many items: impossible
        return 0
    necessary = buckets*lower
    if items == necessary:  # just enough items to meet the minimum requirement
        return 1
    if items < necessary:   # too few items: impossible
        return 0
    # put the minimum required number in each bucket, leaving
    # items - necessary
    # to distribute
    left = items - necessary
    # We have put 'lower' items in each bucket, so each bucket can now take
    # at most (upper - lower) more
    # any more, and the bucket is overfull
    over = upper + 1 - lower
    # maximal number of buckets we can put more than upper in at all
    # after we fulfilled the minimum requirement
    m = left // over
    # We start with the number of ways to distribute the items disregarding
    # the upper limit
    ws = distributions(left,buckets)
    # Sign for inclusion-exclusion, (-1)**k
    sign = -1
    # Number of overfull buckets
    k = 1
    while k <= m:
        # Add or subtract the number of ways to distribute
        # 'left' items to 'buckets' buckets with
        # k buckets overfull
        #
        # nCr(buckets,k) choices of the buckets we overfill at the start
        #
        # That leaves (left - k*over) items to distribute.
        ws += sign * nCr(buckets,k) * distributions(left - k*over,buckets)
        # flip sign and increment number of overfull buckets
        sign = -sign
        k += 1
    return ws
导入数学
def nCr(n,r):
f=数学阶乘
返回f(n)/f(r)/f(n-r)
def itemCount_cal(目标、项目、最小值):
返回目标-项目*最小值
def分配(itemCount、bucketCount):
#有一种方法可以将0个项目分配到任意数量的bucket:all get 0个项目
如果itemCount==0:
返回1
#我们不能分发少于0个项目,我们至少需要一个存储桶
如果itemCount<0或bucketCount<1:
返回0
#如果只有一个水桶,只有一条路
如果bucketCount==1:
返回1
#获得所有可能的解决方案
#将n个项目分配到b个存储桶的方法数为
#不合格报告(n+b-1,n)
f=数学阶乘
返回f(项目计数+bucketCount-1)/(f(项目计数)*f(bucketCount-1))
def通道(项目、铲斗、下部、上部):
如果上限<下限:#上限小于下限:不可能
返回0
如果桶*上部<项目:#项目太多:不可能
返回0
必要=铲斗*较低
如果项目==必要:#刚好足够满足最低要求的项目
返回1
如果项目<必要:#项目太少:不可能
返回0
#在每个桶中放入所需的最小数量,留下
#项目-必要
#分发
左=项目-必要
#我们在每个桶中放入了“较低”的物品,因此每个桶现在都可以
#最多(上-下)更多
#再多的话,桶就满了
上方=上方+1-下方
#我们可以放入的桶的最大数量超过上限
#在我们达到最低要求之后
m=剩余//剩余
#我们首先介绍了分配项目的方法的数量
#上限
ws=分布(左,桶)
#包含排除符号,(-1)**k
符号=-1
#满桶数
k=1

而k是您最初示例中篮子的容量100个项目?在您编写的程序中,听起来好像您在说您的购物篮容量为20,您在4种商品类型中进行选择,这与说每个商品至少有计数20,您的购物篮容量为100是一样的。我认为您应该停止在示例中使用百分比,因为实际上,你只需要对正整数进行这些运算。只要说你想要100个项目,其中25个是苹果等等…无论如何+1,我希望看到一个t的封闭公式
m = min { bucketCount, floor(itemCount/(upperLimit+1)) }
import math

def nCr(n,r):
    f = math.factorial
    return f(n) / f(r) / f(n-r)

def itemCount_cal(target, items, minValue):
    return target- items*minValue

def distributions(itemCount, bucketCount):
    # There's one way to distribute 0 items to any number of buckets: all get 0 items
    if itemCount == 0:
        return 1
    # we can't distribute fewer than 0 items, and we need at least one bucket
    if itemCount < 0 or bucketCount < 1:
        return 0
    # If there's only one bucket, there's only one way
    if bucketCount == 1:
        return 1
    #get all possible solutions
    # The number of ways to distribute n items to b buckets is
    # nCr(n+b-1,n)
    f = math.factorial
    return f(itemCount + bucketCount-1)/(f(itemCount) *  f(bucketCount-1))

def ways(items,buckets,lower,upper):
    if upper < lower: # upper limit smaller than lower: impossible
        return 0
    if buckets*upper < items: # too many items: impossible
        return 0
    necessary = buckets*lower
    if items == necessary:  # just enough items to meet the minimum requirement
        return 1
    if items < necessary:   # too few items: impossible
        return 0
    # put the minimum required number in each bucket, leaving
    # items - necessary
    # to distribute
    left = items - necessary
    # We have put 'lower' items in each bucket, so each bucket can now take
    # at most (upper - lower) more
    # any more, and the bucket is overfull
    over = upper + 1 - lower
    # maximal number of buckets we can put more than upper in at all
    # after we fulfilled the minimum requirement
    m = left // over
    # We start with the number of ways to distribute the items disregarding
    # the upper limit
    ws = distributions(left,buckets)
    # Sign for inclusion-exclusion, (-1)**k
    sign = -1
    # Number of overfull buckets
    k = 1
    while k <= m:
        # Add or subtract the number of ways to distribute
        # 'left' items to 'buckets' buckets with
        # k buckets overfull
        #
        # nCr(buckets,k) choices of the buckets we overfill at the start
        #
        # That leaves (left - k*over) items to distribute.
        ws += sign * nCr(buckets,k) * distributions(left - k*over,buckets)
        # flip sign and increment number of overfull buckets
        sign = -sign
        k += 1
    return ws