raf*_*uto 4 javascript combinations permutation
一个9人小组可以以几种方式在2个,3个和4个不相交的亚组中工作?如何通过javascript回溯生成所有可能性。
例:
Gs = group([aldo,beat,carla,david,evi,flip,gary,hugo,ida],[2,2,5]);
console.log(Gs); // [[aldo,beat],[carla,david],[evi,flip,gary,hugo,ida]], ...
Run Code Online (Sandbox Code Playgroud)
请注意,我不希望组成员进行排列。即[[aldo,beat],...]与[[beat,aldo],...]相同。但是,[[aldo,beat],[carla,david],...]和[[carla,david],[aldo,beat],...]之间存在差异。
*请没有图书馆。
如果您只需要将9人组成的小组划分为2个,3个和4个人的3个子组的方式,那么使用数学方法C(计算组合数的函数)就很容易计算。
C(9, 2)。C(7, 3)。C(4, 4)。但是C(n, n)总是1。因此,将9个人组成的小组分为2个,3个和4个人的3个子组的方法数目为C(9, 2) * C(7, 3) * C(4, 4)。这可以简化为C(9, 2) * C(7, 3),这是36 * 35这是1260。
我们可以编写一个函数来为我们计算:
function ways(n) {
var l = arguments.length, w = 1;
for (var i = 1; i < l; i++) {
var m = arguments[i];
w *= combinations(n, m);
n -= m;
}
return w;
}
Run Code Online (Sandbox Code Playgroud)
为了使此功能正常工作,我们需要定义以下功能combinations:
function combinations(n, k) {
return factorial(n) / factorial(n - k) / factorial(k);
}
Run Code Online (Sandbox Code Playgroud)
最后,我们需要为以下函数定义功能factorial:
function factorial(n) {
var f = n;
while (--n) f *= n;
return f;
}
Run Code Online (Sandbox Code Playgroud)
然后,我们计算方式的数量如下:
alert(ways(9, 2, 3)); // 1260
Run Code Online (Sandbox Code Playgroud)
您可以在此处查看演示:http : //jsfiddle.net/bHSuh/
请注意,我们不需要指定4个人的最后一个子组,因为这是隐含的。
但是,我相信您想生成每种可能的方法。这是amb操作员理想的选择。因此,我们要做的第一件事就是用ambJavaScript 编写运算符:
function amb(options, callback) {
var length = options.length;
for (var i = 0; i < length; i++) {
try {
callback(options[i]); // try the next option
return; // no problem, quit
} catch (e) {
continue; // problem, next
}
}
throw new Error("amb tree exhausted"); // throw a tantrum
}
Run Code Online (Sandbox Code Playgroud)
接下来,我们将编写一个函数,该函数从索引列表中选择一组给定的项目:
function pick(list, items) {
var length = list.length, selected = [], rest = [];
for (var i = 0; i < length; i++) {
if (items.indexOf(i) < 0) rest.push(list[i]);
else selected.push(list[i]);
}
return [selected, rest];
}
Run Code Online (Sandbox Code Playgroud)
我们还需要一个函数来生成索引列表:
function getIndices(length) {
var indices = [];
for (var i = 0; i < length; i++)
indices.push(i);
return indices;
}
Run Code Online (Sandbox Code Playgroud)
最后,我们将group递归地实现该函数:
function group(options, divisions) {
var subgroup = [], groups = [], n = 0;
var indices = getIndices(options.length);
var division = divisions.shift(), remaining = divisions.length;
try {
amb(indices, select);
} catch (e) {
return groups;
}
function select(index) {
subgroup.push(index);
if (++n < division) {
try { amb(indices.slice(index + 1), select); }
catch (e) { /* we want to continue processing */ }
} else {
var subgroups = pick(options, subgroup);
if (remaining) {
var children = group(subgroups.pop(), divisions.slice());
var length = children.length;
for (var i = 0; i < length; i++)
groups.push(subgroups.concat(children[i]));
} else groups.push(subgroups);
}
n--;
subgroup.pop();
throw new Error;
}
}
Run Code Online (Sandbox Code Playgroud)
现在您可以按以下方式使用它:
var groups = group([
"aldo", "beat", "carla",
"david", "evi", "flip",
"gary", "hugo", "ida"
], [2, 3]);
Run Code Online (Sandbox Code Playgroud)
再次注意,您不需要指定最后一个包含4个人的子组,因为这是隐含的。
现在让我们看看输出是否如我们预期的那样:
console.log(groups.length === ways(9, 2, 3)); // true
Run Code Online (Sandbox Code Playgroud)
妳去 确切地说,有1260种方法可以将一个9人的小组分为3个子小组,每个小组分别为2、3和4人。
现在我知道我的group功能看起来有些令人生畏,但实际上非常简单。尝试阅读它并了解发生了什么。
假设您是9个人的老板。您如何将他们分为2、3和4个人的3个子组?这正是我的group功能工作的方式。
如果过一会儿您仍然无法理解逻辑,那么我将更新我的答案并group详细解释该功能。祝你好运。
顺便说一句,我刚刚意识到对于这个问题你并不需要amb。您可以简单地使用forEach。由于没有try-catch块,因此生成的代码会更快:
function group(options, divisions) {
var subgroup = [], groups = [], n = 0;
var indices = getIndices(options.length);
var division = divisions.shift(), remaining = divisions.length;
indices.forEach(select);
return groups;
function select(index) {
subgroup.push(index);
if (++n < division) indices.slice(index + 1).forEach(select);
else {
var subgroups = pick(options, subgroup);
if (remaining) {
var children = group(subgroups.pop(), divisions.slice());
var length = children.length;
for (var i = 0; i < length; i++)
groups.push(subgroups.concat(children[i]));
} else groups.push(subgroups);
}
subgroup.pop();
n--;
}
}
Run Code Online (Sandbox Code Playgroud)
由于我们不再使用amb该程序,因此执行时间减少了十倍。亲自查看结果:http : //jsperf.com/amb-vs-foreach
我还终于创建了上面程序的演示小提琴:http : //jsfiddle.net/Ug6Pb/