假设您有一个带 N 插槽的圆圈(如下所示)。 您的目标是在每个插槽中最终获得指定数量的珠子,并且您有一个大小 N 的阵列,其中包含每个插槽中所需的珠子数量。例如,如果阵列是{1,5,3},那么你需要在插槽1中最终得到1个珠子,插槽2中有5个珠子,插槽3中有3个珠子。你有无限量的珠子。
您可以“解锁” X 广告位。解锁插槽后,您可以开始在该插槽中放置珠子。您可以移动已经在插槽中的珠子,但只能顺时针移动。
为了解决问题,珠子必须移动的最小距离是多少?
以下是一个例子:
N = 6,X = 2.数组:{2,5,4,2,6,2}
解锁插槽2和5.将11个珠子放入插槽2并行进总距离8以到达插槽2,3和4.将10个珠子放入插槽5并行进总距离6以到达插槽5,6和1. 8 + 6 = 14,所以答案是14。
答案 0 :(得分:0)
问题有一些注意事项:
此处建议的算法将遍历所有combinations个可能的插槽选择,并选择具有最低移动的组合。因此时间复杂度 O(n!/ [(n-x)!x!])。
我认为应该有一个更有效的算法,不需要访问所有组合,但我没有找到任何允许这种情况的数学模式。
以下是JavaScript代码段中的算法:
function optimalCollectors(beadCounts, collectorCount) {
// Initialisation
var n = beadCounts.length;
if (n < collectorCount) return {error: "not enough slots"};
var beads = beadCounts.reduce(function (beads, beadCount) {
return beads + beadCount;
});
var cost = beadCounts.reduce(function (cost, beadCount, idx) {
return cost + beadCount * (idx+1);
});
var solution = {
cost: cost, // too large, to make sure it gets improved
slots: [] // numbers of the slots chosen for the solution
};
var collectorSlots = Array(collectorCount);
function findNextCollector(collectorNo, startSlot, cost, beads) {
var addBeads = 0;
for (var slot=startSlot; slot<=n-collectorCount+collectorNo; slot++) {
collectorSlots[collectorNo] = slot;
// progressively calculate total cost, and number of beads
// "in front" of the currently tried slot.
cost -= beads;
beads += addBeads - beadCounts[slot];
if (collectorNo == collectorCount - 1) { // all slots chosen
if (cost < solution.cost) { // found a current best
solution.cost = cost;
// copy currently selected slot numbers:
solution.slots = collectorSlots.slice(0);
}
} else {
findNextCollector(collectorNo+1, slot+1, cost, beads);
}
if (collectorNo) {
cost += beadCounts[slot] * (slot + 1 - startSlot);
} else {
cost += beadCounts[slot] * (n - 1);
addBeads = beadCounts[slot];
}
}
}
findNextCollector(0, 0, cost, beads);
return solution;
}
function randomInput(n) {
// The random values are in the range 0..n-1. This is just
// a convenient choice, in reality there has not to be a limit.
return Array.from({length: n}, x => Math.floor(Math.random() * n));
}
// Link with I/O
var beads = document.getElementById('beads');
var collectors = document.getElementById('collectors');
var randomize = document.getElementById('randomize');
var calculate = document.getElementById('calculate');
var output = document.getElementById('output');
// Capture events
randomize.onclick = function() {
var n = 5 + Math.floor(Math.random() * 7);
beads.value = randomInput(n).join(',');
collectors.value = 2 + Math.floor(Math.random() * (n/2-2));
calculate.onclick();
};
calculate.onclick = function() {
var beadCounts = beads.value.split(',').map(Number);
var collectorCount = Number(collectors.value);
var solution = optimalCollectors(beadCounts, collectorCount);
if (solution.error) {
output.textContent = 'Error: ' + solution.error;
return;
}
output.textContent =
'\nInput: ' + JSON.stringify(beadCounts) +
'\nNumber of moves: ' + solution.cost +
'\nChosen slots (0-based): ' + JSON.stringify(solution.slots);
};
&#13;
Comma-separated list of number of beads per slot:<br/>
<input id="beads" size="30" value="2, 5, 4, 2, 6, 2">
<button id="randomize">Randomize</button><br/>
Number of bead-collecting slots:<br/>
<input id="collectors" size="3" value="2"></br>
<button id="calculate">Find collector slots minimising cost</button></br>
<pre id="output"></pre>
&#13;