Php 在一次传递中将帐户(用整数表示)平衡到接近0的最佳方法
我有一系列的银行账户,每个月都有最低的付款要求,我正试图找出逻辑,以获得最佳的付款计划。以下是阵列结构:Php 在一次传递中将帐户(用整数表示)平衡到接近0的最佳方法,php,algorithm,sorting,logic,Php,Algorithm,Sorting,Logic,我有一系列的银行账户,每个月都有最低的付款要求,我正试图找出逻辑,以获得最佳的付款计划。以下是阵列结构: array(4) { ["account_one"]=> array(9) { ["account"]=> string(21) "Account One" ["balance"]=> int(2500) ["minimum_payment"]=> int(1000) } ["account_two"]=
array(4) {
["account_one"]=>
array(9) {
["account"]=>
string(21) "Account One"
["balance"]=>
int(2500)
["minimum_payment"]=>
int(1000)
}
["account_two"]=>
array(9) {
["account"]=>
string(16) "Account Two"
["balance"]=>
int(1500)
["minimum_payment"]=>
int(500)
}
["account_three"]=>
array(9) {
["account"]=>
string(10) "Account Three"
["balance"]=>
int(3000)
["minimum_payment"]=>
int(750)
}
["account_four"]=>
array(9) {
["account"]=>
string(14) "Account Four"
["balance"]=>
int(3000)
["minimum_payment"]=>
int(750)
}
}
在本例中,帐户中的总金额为10000,需要在每个帐户之间移动,以满足最低付款要求。付款计划还需要尽可能高效,以最少的付款次数满足要求。这是一个简单的例子,但在生产中,我们可能有15个或更多的帐户,最低付款金额不同
到目前为止,我所得到的并不多,因为我正在努力掌握我需要的总体逻辑:
$accounts_by_amount (array of accounts sorted by balance high to low)
$accounts_reversed ($accounts_by_amount in reverse order)
$schedule = array()
foreach $accounts_by_amount as $account_a
foreach $accounts_reversed as $account_b
if $account_a['minimum_payment'] > $account_b['mininum_payment']
// use higher minimum payment to reduce total payments needed
$schedule_b[] = array(
'from' => $account_a['account'],
'to' => $account_b['account'],
'amount' => $account_a['minimum_payment'],
);
else
continue;
if $schedule_b
$schedule += $schedule_b
else
continue
显然,这不起作用,但我认为我可能使循环中的循环变得过于复杂。我不是在寻找一个真正为我编写代码的人,更多的是告诉我,我对这个逻辑有多么愚蠢,以及如何将这个计划与最低付款数量结合起来的粗略想法。排除计划逻辑,我写了这样的东西来转移和平衡账户之间的金额。希望这有帮助。这是JavaScript/我将让您使用PHP来尝试 基本上,我们计算可用余额,从高到低对可用余额进行排序,并在平衡账户的同时从开始到结束进行迭代。这也不是您可以进行的最小转账次数,但如果您在每次迭代后重新计算最佳可用帐户,您就可以得到该数目 在最坏的情况下,它将在O(n)处执行,在真正最坏的情况下,您的最佳帐户中没有足够的资金,这将使它跳过while循环。但这意味着你会有真正的问题,而不是大O符号
let accounts = [
{ id: 2, balance: 6000, minpay: 4000 },
{ id: 1, balance: 5000, minpay: 2000 },
{ id: 3, balance: 4000, minpay: 4000 },
{ id: 4, balance: 4000, minpay: 5000 },
{ id: 6, balance: 3000, minpay: 6000 },
{ id: 5, balance: 3000, minpay: 5000 }
];
// create a map of workable balances.
let workableBalance = accounts.map(v => {
return {
id: v.id,
value: v.balance - v.minpay
}
}).sort((a,b) => {return b.value-a.value}); // sort descending;
let cursorFromBeginning = 0;
let cursorFromEnd = workableBalance.length - 1;
if (workableBalance[cursorFromEnd].value > 0) {
console.log('All accounts have sufficient money in them.');
return; // terminate.
}
if (workableBalance[cursorFromBeginning].value < 0) {
console.log(`No way that we'll balance the accounts. The best account is in negatives.`);
return; // terminate.
}
console.log('Present state of things: ', workableBalance);
while(cursorFromBeginning < cursorFromEnd) {
// Get the balance from least available account.
// Validate that the worst account actually needs money.
let worstAccount = workableBalance[cursorFromEnd];
if (worstAccount.value >= 0) {
console.log(`All good! We're balanced`, workableBalance);
return;
}
let bestAccount = workableBalance[cursorFromBeginning];
if (bestAccount.value == 0) {
cursorFromBeginning++;
continue;
}
// Can this account single-handedly balance the next worst account?
if (bestAccount.value >= Math.abs(worstAccount.value)) {
// Balance the account.
console.log(`Moving $${bestAccount.value} from account ${bestAccount.id} to ${worstAccount.id} - balancing the whole account.`);
bestAccount.value += worstAccount.value;
worstAccount.value = 0;
cursorFromEnd--;
}
else {
// Balance as much as we can.
console.log(`Moving $${bestAccount.value} from account ${bestAccount.id} to ${worstAccount.id} - balancing the account partially.`);
bestAccount.value = 0;
worstAccount.value += bestAccount.value;
cursorFromBeginning++;
}
}
console.log('Things after some magic: ', workableBalance);
let账户=[
{id:2,余额:6000,minpay:4000},
{id:1,余额:5000,minpay:2000},
{id:3,余额:4000,minpay:4000},
{id:4,余额:4000,minpay:5000},
{id:6,余额:3000,minpay:6000},
{id:5,余额:3000,minpay:5000}
];
//创建一张可行平衡图。
让workableBalance=accounts.map(v=>{
返回{
id:v.id,
价值:v.balance-v.minpay
}
}).sort((a,b)=>{return b.value-a.value});//降序排序;
让CursorFromStart=0;
让cursorFromEnd=可工作平衡。长度-1;
if(可工作平衡[cursorFromEnd]。值>0){
console.log('所有帐户都有足够的钱');
return;//终止。
}
if(可工作平衡[CursorFromStart]。值<0){
log(`我们不可能平衡帐户。最好的帐户是负数。`);
return;//终止。
}
console.log('事物的当前状态:',可用平衡);
while(CursorFromStart=0){
log(`All good!We's balanced`,workableBalance);
回来
}
让bestAccount=可操作余额[游标从开始];
如果(bestAccount.value==0){
游标fromStart++;
持续
}
//这个账户能单独平衡下一个最差的账户吗?
if(bestAccount.value>=Math.abs(worstAccount.value)){
//结清帐目。
log(`Moving${bestAccount.value}从帐户${bestAccount.id}移动到${worstAccount.id}-平衡整个帐户。`);
bestAccount.value+=worstAccount.value;
worstAccount.value=0;
cursorFromEnd--;
}
否则{
//尽量保持平衡。
log(`Moving${bestAccount.value}从帐户${bestAccount.id}移动到${worstAccount.id}-部分平衡帐户。`);
bestAccount.value=0;
worstAccount.value+=bestAccount.value;
游标fromStart++;
}
}
log('Things after some magic:',workableBalance);
我多次阅读了您的问题,但仍然不清楚您想了解/完成什么。您示例中的所有帐户余额都足以支付每个帐户的最低付款。Dave,这可能是一个不好的示例,因为有时在资金从另一个帐户转入该帐户之前,余额中不会有足够的款项支付。账户之间总共有10万美元,我需要一个付款计划,在每个账户之间移动资金以达到最低付款。我会试着改写原来的问题。我也很困惑。你提到了一个不同付款的时间表,但我没有看到描述这些付款和变化的条款,也没有处理基于时间的流程。此外,如果没有基于时间的输入,则时间因素无关紧要:您需要涵盖每个帐户的所有付款总额。请为输入和输出提供清晰的示例和问题案例。我们将需要与数组项的时间关联,例如付款到期日。如果所有人的付款到期日都一样,那就更好了。我认为您要做的是在N个帐户之间进行最小数量的转账,以便满足他们的最小付款值。另外,知道我们的总收入是否总是大于需要支付的金额也将是一件好事。这正是我所寻找的。因为没有截止日期,所以这是有效的。我将尝试将类似的东西引入PHP。谢谢很高兴听到!我很感激绿色的勾号:)