如果您只需要路數一組9人,可分爲每2,3和4人3個亞組則這很容易使用C
(計算組合數的函數)以數學方式進行計算。
- 首先你有9個人,你需要選擇2人。因此你做
C(9, 2)
。
- 接下來你有7人,你需要選擇3人。因此你做
C(7, 3)
。
- 最後,你有4人,你需要選擇4人。因此你做
C(4, 4)
。然而C(n, n)
始終是1。
因此的方式來劃分的一組9人進入的2,3和4人是C(9, 2) * C(7, 3) * C(4, 4)
3個亞組的數目。這可以簡化爲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;
}
要啓用此功能工作,我們需要定義功能combinations
:
function combinations(n, k) {
return factorial(n)/factorial(n - k)/factorial(k);
}
最後,我們需要定義功能factorial
:
function factorial(n) {
var f = n;
while (--n) f *= n;
return f;
}
然後我們計算出數字方法如下:
alert(ways(9, 2, 3)); // 1260
您可以在這裏看到演示:http://jsfiddle.net/bHSuh/
需要注意的是,我們並不需要,因爲這是隱含指定的4人最後的分組。
但是我相信你想要生成每種可能的方式。這是運營商非常適合的事情。所以,我們要做的第一件事就是用JavaScript編寫amb
操作:
下一步,我們將寫一個挑選一組給定的項目從索引列表的功能:
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];
}
我們還需要將生成的索引列表的功能:
function getIndices(length) {
var indices = [];
for (var i = 0; i < length; i++)
indices.push(i);
return indices;
}
最後,我們將遞歸實現group
功能:
0現在
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;
}
}
,你可以按如下方式使用它:再次
var groups = group([
"aldo", "beat", "carla",
"david", "evi", "flip",
"gary", "hugo", "ida"
], [2, 3]);
請注意,您並不需要指定的4人最後的分組,因爲它暗示。
現在讓我們看看輸出是否是因爲我們希望它是:
console.log(groups.length === ways(9, 2, 3)); // true
你去那裏。確切地說,有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--;
}
}
因爲我們不使用amb
了該計劃已減少十倍的執行時間。見自己的結果:http://jsperf.com/amb-vs-foreach
而且我終於創建了上述程序的演示小提琴:http://jsfiddle.net/Ug6Pb/
你不想使用庫,所以你基本上是尋找一個算法?你有嘗試過什麼嗎?你可以從http://stackoverflow.com/questions/127704/algorithm-to-return-all-combinations-of-k-elements-from-n或http://stackoverflow.com/questions/12991758/得到一些靈感。創建所有可能的K組合的n項目在C(第二個鏈接是接近你想要的,儘管在另一種語言)。 – Stijn
我更新了我的答案,並使「羣組」功能快了十倍。 –