我已经坚持这个问题一个星期,我搜索过,我发现的结果似乎与我想做的事情不符。
问题: 一个人会购买东西,收银员会根据人的账单回馈变更。
我做了什么:我检测买家总共有多少钱以及每张美元钞票的数量,比较买家是否有所需金额
但现在我需要获得买方必须从购买价格中扣除所需的账单金额并将其移除以完成付款。一个贪婪的算法对我来说没关系,我可以从最高账单开始,然后从那里开始,直到他的账单总和少于或等于购买总额。然后收银员只留下遗体
我提供了改变的代码,这是一个简单的贪婪算法,通过划分和得到除法的余数。我相信要解决我的问题,我可以采取类似于我为换钱所做的事情。
账单是:1,5,10,20,50,100。
代码示例:
int Value = 150 //value that needs to be paid
int q100 = 1; //dollar bills amount that needs to subtract from Value
int q50 = 0;
int q20 = 0;
int q10 = 5; //this example I've one $50 dollar bill and five $10, how can I subtract from here no matter how many bills I've
int q5 = 0;
int q1 = 0;
int q05 = 0;
decimal Total = 0;
int Total = (n100 * 100) + (n50 * 50) + (n20 * 20) + (n10 * 10) + (n5 * 5) + (n1 * 1);
if(Value > Total)
{
//Doesn't have enough money
return;
}
//stuck here
任何人都可以带我继续前进吗?我可能在错误的地方寻找。
已编辑:我带着解决方案,跟随Jason Lang部分回答。
for (int i = billValues.Length - 1; i >= 0; i--) // biggest FIRST
{
// basically keep paying with e.g. hundreds as long as the amount
// left is 100+, etc, then go on to 50's etc
while (amountLeftToPay > 0 && myBills[i] > 0)
{
amountLeftToPay -= billValues[i];
myBills[i]--;
paidBills[i]++;
}
}
发生了什么: myBills正在设置之前的值,这是for / while迭代,直到AmountLeftToPay为0或小于0,同时保存客户支付的账单。 (这些账单后来在其他功能中删除,它不适用于基本的C#,它基于游戏的框架。)
然后我将负值变为正乘以-1。该值将被传递给要转换为更改的函数。 以下是我在控制台应用程序上进行调试的一点测试代码:http://pastebin.com/GekLLjB3
最后myBills值是客户在收到任何更改之前剩余的账单,paidBills是已移除的账单。
答案 0 :(得分:0)
首先,任何时候你制作大量的变量,比如数字变量,将其转换为单个数组。更整洁,而且几乎总是更好。
int[] billValues = {1, 5, 10, 20, 50, 100};
然后你就可以拥有你的起始账单的数组,支付的内容以及你得到的变化,而不会出现变量名称的爆炸:
int[] myBills = new int[6]; // which bills I have
int[] paidBills = new int[6]; // what bills I paid
int[] changeBills = new int[6]; // what bills I got as change
这些匹配"插槽"在billValue数组中,所以你实际上并不需要制作所有这些单独的变量。
将支付金额分开:
int amountToPay = 150;
然后,您可以运行一些while循环来从正确的数组中扣除帐单并将其添加到其他数组。您要做的第一件事是循环您的账单并扣除等于或小于amountToPay的最大账单。当每个账单被移交时,您需要跟踪剩余的支付金额。
int amountLeftToPay = amountToPay;
然后,扣除最合适的账单
for(int i = billValues.Length - 1; i >= 0; i--) // biggest FIRST
{
// basically keep paying with e.g. hundreds as long as the amount
// left is 100+, etc, then go on to 50's etc
while (billValues[i] <= amountLeftToPay && myBills[i] > 0)
{
amountLeftToPay -= billValues[i];
myBills[i] --;
paidBills[i] ++;
}
}
此时,您支付的所有账单都已支付。现在可能存在一种情况,即剩余的支付金额大于零,但它比你拥有的任何特定账单要少。要对此进行排序,您需要找出比剩余金额更大的最小账单。所以你需要循环,这次:
int billToUse = -1; // -1 will mean not found
for(int i = 0; i < billValues.Length; i++) // smallest first
{
if(amountLeftToPay <= billValues[i] && myBills[i] > 0)
{
billToUse = i;
break;
}
}
这里我们要记录欠款的数量,如果有的话
int amountOwedAsChange = 0;
if(billToUse >= 0) // i.e. one was found
{
amountOwedAsChange = billValues[billToUse] - amountLeftToPay;
amountLeftToPay = 0;
}
对,这是主场。计算出变更所欠的账单基本上与我们制定支付账单时所做的相同,除非我们可以假设收银机有无限的账单。但你实际上可以兑换原来的#34付款账单&#34;将代码编入功能,并对收银机中的内容进行建模,以便他们只需支付他们所拥有的费用。一旦你把事情分解成变得更容易的功能。您只需将收银机建模为另一个“#34; person&#34;谁自己有一个myBills数组。但就目前而言,我们硬编码更简单的版本,其中收银机总是有他们需要的账单:
for(int i = billValues.Length - 1; i >= 0; i--) // biggest FIRST
{
while (billValues[i] <= amountOwedAsChange)
{
amountOwedAsChange -= billValues[i];
changeBills [i] ++;
}
}
所以在这一点上,amountLeftToPay和amountOwedAsChange都是零,并且信息已经打包到myBills和changeBills中,你可以循环显示这些信息并打印出描述付费内容和变化的文本。
对于添加点,您可以将其展开以轻松覆盖硬币。您只需以美分编码所有内容,并将所有美元值乘以100,根据需要扩展billValues表(并增加其他数组的大小以匹配)。
答案 1 :(得分:0)
这是一种可以将金额细分为所需注释的方法:
var bills = new [] { 1, 5, 10, 20, 50, 100, };
var value = 150;
var breakdown =
bills
.OrderByDescending(x => x)
.Aggregate(new { value, bills = new List<int>() },
(a, b) =>
{
var v = a.value;
while (v >= b)
{
a.bills.Add(b);
v -= b;
}
return new { value = v, a.bills };
})
.bills
.GroupBy(x => x)
.Select(x => new { Bill = x.Key, Count = x.Count() });
这让我:
您也可以轻松扩展此项以计算硬币。
var bills = new double[] { 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 5, 10, 20, 50, 100, };
var value = 213.47;
var breakdown =
bills
.OrderByDescending(x => x)
.Aggregate(new { value, bills = new List<double>() },
(a, b) =>
{
var v = a.value;
while (v >= b)
{
a.bills.Add(b);
v -= b;
}
return new { value = v, a.bills };
})
.bills
.GroupBy(x => x)
.Select(x => new { Bill = x.Key, Count = x.Count() });
这给出了: