【问题标题】:Algo for payment device amount suggestion for cash payment现金支付的支付设备金额建议算法
【发布时间】:2018-06-11 14:09:44
【问题描述】:

我已经完成了背包问题等,但我不确定这个问题是否以某种方式属于该领域,无论如何,如何解决它。问题来了:

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我无法想出一个算法,虽然我一直觉得它是背包问题,但给定值有多个答案?

【问题讨论】:

  • 您将如何确定这些是支付金额的前 6 种选择,使用 dp 您可以计算使用上述面额支付金额的方式有多少种,假设有 8 种方式使用上述面额支付 87 美元,但我们如何才能确定这些是前 6 种选择等等……我们是否应该根据使用的高面额金额对我们的选择进行排序?
  • 您的要求不明确。是什么让选择比其他人更好? 5x100 比 4x80+1x20+1x5+x2 或其他方式更好吗?究竟是如何确定哪些选项是“顶级”的?
  • @libik,即使当我被问到时,Q 的框架也很模糊,但一个指标可以是使用较少数量的钞票,或者最接近的总和是首选或两者兼而有之。对于 87:选择 1:4x20+2+5,选择 2:4*20+10,选择 3:5*x20
  • @zenwraight,客户很少支付确切的金额,但这肯定是一种选择,我回复了 libik 的类似 Q 的最佳选择。
  • @curiousengineer 如果时间复杂度不是约束,那么对于给定的输入量 n,您也可以运行递归函数,它将遍历所有组合并为您提供不同方式的答案。

标签: algorithm sorting dynamic-programming


【解决方案1】:

要提到的重要一点是,您应该获得更具体的要求。与客户坐在一起,准备例子并问他们问题非常重要:“我必须支付 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 ] } ]

您可以更多地使用这些指标并找出最适合您的输出。

【讨论】:

  • 惊人的答案,你的要求是正确的。我对javascript不太了解,请问payments.reduce在做什么?
  • @curiousengineer - 你不必知道确切的语法(你可以谷歌它 - javascript数组减少)。但它计算payments 数组中所有值的总和。所以如果你只是循环它和sum += payments[i],它会是一样的。但是使用 reduce,它是单行的。
猜你喜欢
  • 1970-01-01
  • 2016-10-22
  • 1970-01-01
  • 1970-01-01
  • 2015-04-13
  • 1970-01-01
  • 2015-10-11
  • 2013-11-12
相关资源
最近更新 更多