我已经完成了背包问题,但是我不确定这个问题是否会在某个方面落在那个区域,无论如何,如何解决它。这是一个问题:
Suppose we are given a set of denominations {1, 2, 10, 20, 50, 100}. A customer is checking out and is paying in cash. How we suggest the top 6 or top x choices on our own payment screen based on what amount the customer may have handed over. For example if customer has to pay 87$, customer might hand over 5 bills of 100, or 4 bills of 20 and a 5 and a 2, etc
我无法想出一个算法,虽然我一直觉得这是围绕背包问题,但对给定值有多个答案?
答案 0 :(得分:0)
值得一提的是,您应该获得更具体的要求。与客户坐在一起,准备示例并向他们提问是非常重要的:"我必须支付87,我给你87x $ 1,是不是好,为什么"。从更明显的角度来看,你得到:"什么是更好的50x2或50 + 20 + 20以及为什么"。要创建任何算法,首先需要说明你将如何以人为本(无限时间和耐心)然后你可以实现它。
这里一个非常简单的指标是,您希望价值尽可能接近实际金额,而且您不想用太多账单支付,对吗?
所以我们必须找到所有的解决方案,然后计算得分(更少的账单和更接近目标值的更好),按分数排序并采取' x'最好的。
你可以升级"得分"功能与" 10和20"账单是首选,所以他们使用它们给你更好的分数。或者,较低的账单金额比目标价值与账单金额之间的差异更重要,因此您会更多地惩罚账单(比如每10美元的差额与1个账单的罚款相同)
这是基于回溯的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);
&#13;
所有解决方案的输出从最佳到最差排序:
[ { 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 ] } ]
btw:如果我将分数功能更改为
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 ] } ]
您可以使用这些指标进行更多操作,并找出最适合您的输出。