【问题标题】:Algorithm for possible permutations based on percentages基于百分比的可能排列算法
【发布时间】:2017-07-06 20:38:37
【问题描述】:

我希望在 7 个字母集中找到以下 6 个字母的所有可能排列。 [a,b,c,d,e,f]

问题是每个字母对应一个百分比。每 7 个字母集的总百分比需要为 100%

答:0% <= a < 1%

乙:1% <= b <= 5% C:5% < c <= 25% D:25% < d <= 50% 邮箱:50% < e <= 75% 女:75% < f <= 100%

例如,这些是可能的集合:

  • [a,a,a,a,a,a,f] : 所有的 A 都可能是 0% 而 F 可能是 100%
  • [d,d,b,a,a,a,a]:每个 D 可能是 47%。 B 可能占 5%,A 可能占剩余的 1%。

但这些是不可能的:[f,a,a,a,a,a,f][e,e,e,a,a,a,a],因为它们的总数超过 100%。

我一直在尝试用 javascript 来实现,但运气不佳。我能够使用这个小提琴生成所有可能的排列:https://jsfiddle.net/v4s6xk5x/。不幸的是,这没有考虑百分比。

我真的只想要排列而不需要代码。但是任何语言的代码都会有帮助,这样我就可以理解发生了什么。

如果您需要更多信息,请告诉我。

【问题讨论】:

  • 只需在生成期间用它们已经拥有的百分比的最小和最大总和来注释每个选择(注意它们是(多)子集,而不是排列),然后过滤掉那些间隔没有的包括 100 个。
  • True @Will ,它与那个类似,但问题是一个字符代表一个百分比范围而不是一个恒定的特定值,我现在正在研究一种蛮力方法......
  • 递归似乎是显而易见的方法。选择任何保持最小总数 =100% 则保存。
  • @גלעדברקן:没什么区别。假设您有三个不同百分比的a;如果将所有三个百分比都替换为平均值,那么总和将完全相同,并且范围内百分比的平均值保证在该范围内,因为该范围是连续的。

标签: javascript algorithm permutation


【解决方案1】:

递归解决方案示例:

作为输入:

size: 7
letters: [a,b,c,d,e,f]
minval: [0,1,5,25,50,75]
maxval: [1,5,25,50,75,100]

首先创建一个空集和该集的最小值和最大值:

set: []
min: 0
max: 0

然后将此集合传递给递归函数,它应该:

  • 遍历每个字母。
  • 检查集合的最小值+字母的最小值是否
  • 如果是,则创建集合、最小值和最大值的副本,并添加字母和字母的最小值和最大值;否则,继续下一个字母。
  • 如果集合副本的长度等于大小,并且其最大值 >= 100,则这是一个有效集合;打印或添加到输出。
  • 如果设置副本的长度小于大小,则使用 set_copy、min_copy 和 max_copy 进行递归。

这应该适用于任何大小、任何数量的字母以及任何一组最小值和最大值,无论它们是否有序。

这将产生重复,例如:

[a,a,a,a,a,a,f]
[a,a,a,a,a,f,a]
[a,a,a,a,f,a,a]
...

如果您只想生成唯一的解决方案,请开始迭代添加到集合中的前一个字母中的字母。


这是一个代码示例。这是上面列出的步骤的字面翻译,具有附加功能,它仅通过将先前添加的字母的索引传递给递归(变量prev)然后开始从该字母迭代到最后一个来生成唯一的解决方案。如果您想要非唯一的解决方案,请每次从 0 开始迭代。

检查最小值是否为< 100 而不是<= 100 确保所有范围都排除低阈值并包含高阈值。

请注意,所有由addLetter() 作为参数接收的变量或在addLetter() 内用var 声明的所有变量都是局部变量,并且对于每个递归都是独立的。

function rangeSet(size, letters, minval, maxval) {
    addLetter([], 0, 0, 0);

    function addLetter(set, min, max, prev) {
        for (var lt = prev; lt < letters.length; lt++) {
            if (min + minval[lt] < 100) {
                var set_copy = set.concat([letters[lt]]);
                var min_copy = min + minval[lt];
                var max_copy = max + maxval[lt];
                if (set_copy.length == size) {
                    if (max_copy >= 100) {
                        document.write(set_copy + "<br>");
                    }
                }
                else addLetter(set_copy, min_copy, max_copy, lt);
            }
        }
    }
}

rangeSet(7, ['a','b','c','d','e','f'], [0,1,5,25,50,75], [1,5,25,50,75,100]);

【讨论】:

  • 我没有注意到您混合了独占和包含范围,例如 5 &lt; c &lt;= 25,但这很容易解决。
  • 好吧,我想我有一个好的开始。尽管继续下一封信,但我遇到了一个问题。据我了解,在迭代 a 时,集合的最小值 + 字母的最小值将始终为 0。不是这样吗?这是我的新小提琴:jsfiddle.net/qkkqofbf
  • @Orcinuss 对每个字母的迭代应该通过递归函数内部的循环来完成,而不是使用在它外部定义的变量。
  • 我认为我将字母推送到片场的点是错误的。那,或者我的整个功能是错误的。目前,该函数将添加 7 个 A,然后进行迭代。我最终得到[a,a,a,a,a,a,a,b,c,d,e,f]。任何帮助,将不胜感激。这是我的小提琴:jsfiddle.net/qkkqofbf
  • @Orcinuss "lt" 不应该是全局变量;使用for (var lt ... 将每个递归级别分开。
猜你喜欢
  • 2020-12-09
  • 2016-05-30
  • 1970-01-01
  • 2021-09-10
  • 1970-01-01
  • 2023-03-31
  • 2019-06-03
  • 2020-05-21
  • 2015-10-06
相关资源
最近更新 更多