要提到的重要一点是,您应该获得更具体的要求。与客户坐在一起,准备例子并问他们问题非常重要:“我必须支付 87,我给你 87x$1,好还是不好以及为什么”。从更明显的角度来看,您会得到:“50x2 或 50+20+20 更好,为什么”。要创建任何事物的算法,您首先需要能够说出您作为人类将如何进行(无限的时间和极大的耐心),然后您可以实施它。
这里的一个非常简单的指标是,您希望价值尽可能接近实际金额,并且您不想支付太多账单,对吧?
所以我们必须找到所有的解决方案,然后计算分数(账单越少,越接近目标值越好),按分数排序并取“x”最好的。
您可以升级“评分”功能,即首选“10 和 20”纸币,以便使用它们为您提供更好的评分。或者较低的账单金额比目标值和账单总和之间的差额更重要,因此您对账单的处罚更多(就像每 10 美元的差额与多一张账单的处罚相同)
这是基于回溯的工作 javascript 代码。
// const countables = [100, 50, 20, 10, 2, 1];
// const targetAmount = 87;
const countables = [5, 2, 1];
const targetAmount = 13;
const payments = [];
const solutions = [];
let index = 0;
let end = false;
let i = 0;
while (end === false) {
const sum = payments.reduce((prev, val) => prev + val, 0);
if (sum >= targetAmount) {
solutions.push({
sum,
score: countTheScore(payments, targetAmount, sum),
payments: [...payments],
})
index++;
if (index === countables.length) {
let popped = null;
do {
popped = payments.pop();
} while (popped === countables[countables.length - 1]);
if (payments.length === 0) {
end = true;
}
const indexOfLastNonLowest = countables.indexOf(popped);
index = indexOfLastNonLowest + 1;
} else {
payments.pop();
}
} else {
payments.push(countables[index]);
}
}
function countTheScore(payments, targetAmount, sum) {
amount = payments.length;
difference = sum - targetAmount;
return amount + difference;
}
console.log(solutions.sort((a, b) => a.score - b.score));
// const sortedSolutions = solutions.sort((a, b) => a.score - b.score);
// const bestSolutions = [];
// for (var j=0; j < 5; j++) {
// bestSolutions.push(sortedSolutions[j]);
// }
// console.log(bestSolutions);
它具有从最好到最差排序的所有解决方案的输出:
[ { sum: 13, score: 4, payments: [ 5, 5, 2, 1 ] },
{ sum: 15, score: 5, payments: [ 5, 5, 5 ] },
{ sum: 14, score: 5, payments: [ 5, 5, 2, 2 ] },
{ sum: 13, score: 5, payments: [ 5, 5, 1, 1, 1 ] },
{ sum: 13, score: 5, payments: [ 5, 2, 2, 2, 2 ] },
{ sum: 13, score: 6, payments: [ 5, 2, 2, 2, 1, 1 ] },
{ sum: 13, score: 7, payments: [ 5, 2, 2, 1, 1, 1, 1 ] },
{ sum: 13, score: 8, payments: [ 5, 2, 1, 1, 1, 1, 1, 1 ] },
{ sum: 13, score: 9, payments: [ 5, 1, 1, 1, 1, 1, 1, 1, 1 ] } ]
(分数越低越好)
对于您的原始要求,这将是最佳 5 的输出:
[ { sum: 90, score: 6, payments: [ 50, 20, 20 ] },
{ sum: 90, score: 7, payments: [ 50, 20, 10, 10 ] },
{ sum: 87, score: 7, payments: [ 50, 20, 10, 2, 2, 2, 1 ] },
{ sum: 87, score: 8, payments: [ 50, 10, 10, 10, 2, 2, 2, 1 ] },
{ sum: 90, score: 8, payments: [ 50, 10, 10, 10, 10 ] } ]
顺便说一句:如果我将分数函数更改为
function countTheScore(payments, targetAmount, sum) {
amount = payments.length*3;
difference = sum - targetAmount;
return amount + difference;
}
那么输出可能会更准确地满足您的需要
[ { sum: 90, score: 12, payments: [ 50, 20, 20 ] },
{ sum: 90, score: 15, payments: [ 50, 20, 10, 10 ] },
{ sum: 100, score: 16, payments: [ 100 ] },
{ sum: 90, score: 18, payments: [ 50, 10, 10, 10, 10 ] },
{ sum: 100, score: 19, payments: [ 50, 50 ] } ]
您可以更多地使用这些指标并找出最适合您的输出。