Merge pull request #1783 from siiky/fix/lam-1296/coin-change
LAM-1296 fix: `coin-change`
This commit is contained in:
commit
5dcbf7a60a
2 changed files with 10 additions and 32 deletions
|
|
@ -116,14 +116,8 @@ const getSolution_old = (units, amount, mode) => {
|
||||||
|
|
||||||
const solver = sumService.subsetSum(billList, amount.toNumber())
|
const solver = sumService.subsetSum(billList, amount.toNumber())
|
||||||
const solution = _.countBy(Math.floor, solver.next().value)
|
const solution = _.countBy(Math.floor, solver.next().value)
|
||||||
return _.reduce(
|
return Object.entries(solution)
|
||||||
(acc, value) => {
|
.map(([denomination, provisioned]) => [_.toNumber(denomination), provisioned])
|
||||||
acc.push({ denomination: _.toNumber(value), provisioned: solution[value] })
|
|
||||||
return acc
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
_.keys(solution)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSolution = (units, amount) => {
|
const getSolution = (units, amount) => {
|
||||||
|
|
@ -135,24 +129,13 @@ const getSolution = (units, amount) => {
|
||||||
|
|
||||||
const solutionToOriginalUnits = (solution, units) => {
|
const solutionToOriginalUnits = (solution, units) => {
|
||||||
const billsToAssign = (count, left) => _.clamp(0, count)(_.isNaN(left) || _.isNil(left) ? 0 : left)
|
const billsToAssign = (count, left) => _.clamp(0, count)(_.isNaN(left) || _.isNil(left) ? 0 : left)
|
||||||
|
const billsLeft = Object.fromEntries(solution)
|
||||||
const billsLeft = _.flow(
|
return units.map(
|
||||||
_.map(([denomination, provisioned]) => [BN(denomination), provisioned]),
|
|
||||||
_.reduce((acc, value) => {
|
|
||||||
acc[value[0]] = (acc[value[0]] || BN(0)).plus(value[1])
|
|
||||||
return acc
|
|
||||||
},
|
|
||||||
{}
|
|
||||||
)
|
|
||||||
)(solution)
|
|
||||||
|
|
||||||
return _.map(
|
|
||||||
({ count, name, denomination }) => {
|
({ count, name, denomination }) => {
|
||||||
const provisioned = billsToAssign(count, billsLeft[denomination])
|
const provisioned = billsToAssign(count, billsLeft[denomination])
|
||||||
billsLeft[denomination] -= provisioned
|
billsLeft[denomination] -= provisioned
|
||||||
return { name, denomination, provisioned }
|
return { name, denomination, provisioned }
|
||||||
},
|
}
|
||||||
units
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,13 +143,13 @@ function makeChange(outCassettes, amount) {
|
||||||
const ss_solution = getSolution_old(outCassettes, amount, BILL_LIST_MODES.VALUE_ROUND_ROBIN)
|
const ss_solution = getSolution_old(outCassettes, amount, BILL_LIST_MODES.VALUE_ROUND_ROBIN)
|
||||||
const cc_solution = getSolution(outCassettes, amount)
|
const cc_solution = getSolution(outCassettes, amount)
|
||||||
|
|
||||||
if (!!ss_solution !== !!cc_solution) {
|
if (!cc.check(cc_solution, amount.toNumber())) {
|
||||||
logger.error(new Error(`subset-sum and coin-change don't agree on solvability -- subset-sum:${!!ss_solution} coin-change:${!!cc_solution}`))
|
logger.error(new Error("coin-change provided a bad solution"))
|
||||||
return solutionToOriginalUnits(ss_solution, outCassettes)
|
return solutionToOriginalUnits(ss_solution, outCassettes)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cc.check(cc_solution, amount.toNumber())) {
|
if (!!ss_solution !== !!cc_solution) {
|
||||||
logger.error(new Error("coin-change provided a bad solution"))
|
logger.error(new Error(`subset-sum and coin-change don't agree on solvability -- subset-sum:${!!ss_solution} coin-change:${!!cc_solution}`))
|
||||||
return solutionToOriginalUnits(ss_solution, outCassettes)
|
return solutionToOriginalUnits(ss_solution, outCassettes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,6 @@ const prepare_denominations = denominations =>
|
||||||
const max_denomination_multiplicity = (denom, count, target) =>
|
const max_denomination_multiplicity = (denom, count, target) =>
|
||||||
Math.min(count, Math.floor(target / denom))
|
Math.min(count, Math.floor(target / denom))
|
||||||
|
|
||||||
const has_divisor = (didx, denominations, target) =>
|
|
||||||
denominations
|
|
||||||
.slice(didx)
|
|
||||||
.some(({ denom }) => (target % denom) === 0)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @returns null if there's no solution set;
|
* @returns null if there's no solution set;
|
||||||
* false if there's no solution;
|
* false if there's no solution;
|
||||||
|
|
@ -78,7 +73,7 @@ const solve = (model, target) => {
|
||||||
* of the denominations, or if the target is not divisible by any of the
|
* of the denominations, or if the target is not divisible by any of the
|
||||||
* denominations
|
* denominations
|
||||||
*/
|
*/
|
||||||
if (target > csum || !has_divisor(didx, denominations, target))
|
if (target > csum)
|
||||||
return memo_set(memo, target, denom, false)
|
return memo_set(memo, target, denom, false)
|
||||||
|
|
||||||
let solution = memo_get(memo, target, denom)
|
let solution = memo_get(memo, target, denom)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue