帮我找一个好的算法?
我有一个装满n球的袋子。 (举个例子,我们可以说28个球。)
这个包中的球每个都有1种颜色。袋中有<= 4种不同颜色的球。 (让我们说红色,绿色,蓝色和紫色是可能的。)
我有三个水桶,每个水桶都需要多少个球才能结束。这些数字总数为n。 (例如,让我们说A斗需要最终得到7个球,铲斗B需要最终得到11个球,铲斗C需要最终得到10个球。)
水桶也可能有也可能没有颜色限制 - 他们不接受的颜色。 (铲斗A不接受紫色球或绿球。铲斗B不接受红球。铲斗C不接受紫色球或蓝色球。)
我需要有效且随机地分配球(所有可能性的概率相等)。
我不能随意将球放入有空间接受它们的水桶中,因为这可能会让我遇到这样一种情况,即只有剩余空间的水桶不接受剩下的唯一颜色包。
总的来说,分配球至少有一种可能性。 (我不会有一个只有红色球袋和一些数量> 0的桶不接受红球。)
所有球都被认为是不同的,即使它们是相同的颜色。 (铲斗C获得红球1而不是红球2的可能性之一不同于除了铲斗C得到红球2而不是红球1之外的一切都相同的可能性。)
编辑以添加我的想法:
我不知道这是否具有所有可能性的相同概率,正如我所希望的那样。我还没有想出效率 - 它看起来并不太糟糕。 这包含一个断言,我不确定它是否总是正确的。 如果你知道的话,请评论这些事情。
Choose a ball from the bag at random. (Call it "this ball".)
If this ball fits and is allowed in a number of buckets > 0:
Choose one of those buckets at random and put this ball in that bucket.
else (this ball is not allowed in any bucket that it fits in):
Make a list of colors that can go in buckets that are not full.
Make a list of balls of those colors that are in full buckets that this ball is allowed in.
If that 2nd list is length 0 (There are no balls of colors from the 1st list in the bucket that allows the color of this ball):
ASSERT: (Please show me an example situation where this might not be the case.)
There is a 3rd bucket that is not involved in the previously used buckets in this algorithm.
(One bucket is full and is the only one that allows this ball.
A second bucket is the only one not full and doesn't allow this ball or any ball in the first bucket.
The 3rd bucket is full must allow some color that is in the first bucket and must have some ball that is allowed in the second bucket.)
Choose, at random, a ball from the 3rd bucket balls of colors that fit in the 2nd bucket, and move that ball to the 2nd bucket.
Choose, at random, a ball from the 1st bucket balls of colors that fit in the 3rd bucket, and move that ball to the 3rd bucket.
Put "this ball" (finally) in the 1st bucket.
else:
Choose a ball randomly from that list, and move it to a random bucket that is not full.
Put "this ball" in a bucket that allows it.
Next ball.
答案 0 :(得分:1)
这是一个O(n ^ 3)时间算法。 (3来自桶的数量。)
我们首先绘制一个强力枚举算法,然后提取一个有效的计数算法,然后展示如何采样。
我们使用具有两个嵌套循环的算法进行枚举。外循环遍历球。每个球的颜色无关紧要;只是它可以放在某些水桶而不是其他水桶。在每个外部迭代的开始,我们有一个部分解决方案的列表(到目前为止考虑到球的分配)。内环超过部分解;我们通过以所有有效方式扩展赋值,为新列表添加了几个部分解决方案。 (初始列表有一个元素,空的赋值。)
为了更有效地计算解决方案,我们应用一种称为动态编程或行程编码的技术,具体取决于您如何看待它。如果两个部分解在每个桶中具有相同的计数(在算法的生命周期内具有O(n ^ 3)种可能性),则一个的所有有效扩展都是另一个的有效扩展,反之亦然。我们可以使用计数对列表元素进行注释,并丢弃除了每个&#34;等价类之外的所有代表。部分解决方案。
最后,为了获得一个随机样本,而不是任意选择代表,当我们组合两个列表条目时,我们从每一侧按比例对该方的计数进行抽样。
使用Python代码(O(n ^ 4)以简化;可以进行数据结构改进)。
#!/usr/bin/env python3
import collections
import random
def make_key(buckets, bucket_sizes):
return tuple(bucket_sizes[bucket] for bucket in buckets)
def sample(balls, final_bucket_sizes):
buckets = list(final_bucket_sizes)
partials = {(0,) * len(buckets): (1, [])}
for ball in balls:
next_partials = {}
for count, partial in partials.values():
for bucket in ball:
next_partial = partial + [bucket]
key = make_key(buckets, collections.Counter(next_partial))
if key in next_partials:
existing_count, existing_partial = next_partials[key]
total_count = existing_count + count
next_partials[key] = (total_count, existing_partial if random.randrange(total_count) < existing_count else next_partial)
else:
next_partials[key] = (count, next_partial)
partials = next_partials
return partials[make_key(buckets, final_bucket_sizes)][1]
def test():
red = {'A', 'C'}
green = {'B', 'C'}
blue = {'A', 'B'}
purple = {'B'}
balls = [red] * 8 + [green] * 8 + [blue] * 8 + [purple] * 4
final_bucket_sizes = {'A': 7, 'B': 11, 'C': 10}
return sample(balls, final_bucket_sizes)
if __name__ == '__main__':
print(test())
答案 1 :(得分:0)
我不确定在随机,正确和有效的发行版之间你想要的交易是什么。
如果你想要一个完全随机的发行版,只需选择一个球并将其随机放入一个可以进入的水桶中。它会非常有效但你很容易让水桶溢出。
如果你想确保正确和随机,你可以尝试使所有分布正确并随机选择其中一个,但它可能是非常低效的,因为创建所有分布可能性的基本蛮力算法几乎是在NumberOfBucket ^ NumberOfBalls的复杂性。
创建所有正确案例的更好算法是尝试构建所有案例验证您的两个规则(一个桶B1只能有N1个球,一个桶只接受某些颜色)颜色。例如:
*~/Library/MobileDevice/Provisioning Profiles
(此代码是伪C ++,并不意味着可以运行)
答案 2 :(得分:0)
1首先你在28之间选择7:你有C28,7 = 1184040的可能性。
2秒,你在剩下的21之间选择11:你有C21,11 = 352716种可能性。
剩下的10个元素在C桶中。
在每一步中,如果您的选择不符合规则,则停止并再次执行。
所有东西都有417629852640种可能性(没有限制)。
效率不高,但对于一种选择,它并不重要。如果限制不是限制,则不会浪费太多时间。
如果解决方案很少,则必须限制组合(仅限好颜色)。
答案 3 :(得分:0)
至少在某些情况下,这个问题可以很快解决 首先使用约束将问题减少到更易于管理 大小,然后搜索解空间。
首先,请注意我们可以忽略球的清晰度 算法的主要部分。找到一个解决方案只考虑 颜色,每种颜色随机分配不同的球数是微不足道的 通过在每种颜色内进行洗牌。
在此重述问题并阐明概率相等的概念 是一个简单而正确但可能非常简单的天真算法 低效的:
这样从所有排列的空间中以相等的概率进行采样 并过滤掉那些不符合约束条件的东西,如此均匀 概率得到满足。但是,即使是中度严重 约束,它可能会在找到之前循环数百万次 解。另一方面,如果问题不是很严格,那就是它 会很快找到解决方案。
我们可以通过首先检查约束来利用这两个事实 和每种颜色的球的数量。例如,考虑一下 以下内容:
在使用这些参数的试运行中,天真算法无法找到 2000万次迭代中的有效解决方案。但现在让我们减少 问题
请注意,所有6个紫色球必须进入B,因为它是唯一的一个桶 可以接受他们。所以问题就缩小为:
C需要10个球,并且只能采用红色和绿色。每个有6个。 可能的计数是4 + 6,5 + 5,6 + 4。所以我们必须至少放4个红色和 C中有4个绿色。
我们必须在某处放置10个蓝色球。 C不会接受任何。 B可以拿5 最多;其他5个必须进入A. A最多可以拿7个;其他3 必须进入B.因此,A必须至少取5个蓝色,B必须取 至少3蓝。
此时,问题很简单:检查随机解决方案 减少的问题将在几次尝试中找到有效的解决方案。
对于完全减少的问题,720个排列中的80个是有效的,所以 将找到一个有效的解决方案,概率为1/9。对于原始 28个问题!排列有7个! * 11! * 10! * 80有效 解决方案,找到一个的可能性不到五分之一 十亿。
将上面使用的人类推理转化为减少算法更多 很难,我只会简单地考虑一下。从中推广 上述具体案例:
如果这些没有充分减少特定问题,检查 问题可能产生其他可以编码的减少。
最后:这总能奏效吗?这很难确定,但我怀疑 在大多数情况下,它会因为约束是导致幼稚的原因 算法失败。如果我们可以使用约束来减少问题 对于那些约束无关紧要的人来说,天真的算法 应该找到一个没有太多麻烦的解决方案;有效数量 所有的解决方案应该是相当大的一小部分 可能性。
事后补充:相同的减少技术将改善性能 其他答案也在这里,假设它们是正确的。