| 楼主 rongjun
 | Q: 如何根据总金额计算所需各种面值的充值卡数量? 例如:市面上有5种面值的充值卡,分别为300元、150元、100元、50元、30元,现已知总金额,如何求出各面值的充值卡数量,使得总金额的余额最小。
 
 
   A: 方法一:
 面值300的充值卡计算公式为:
 
 =INT((A2-MOD(MIN(MOD(A2-{0;1;2}*50*(A2>={0;1;2}*50),30)*10^6+{0;1;2}*50),10^4))/300)
 面值150的充值卡计算公式为:
 
 =MOD(INT((A2-MOD(MIN(MOD(A2-{0;1;2}*50*(A2>={0;1;2}*50),30)*10^6+{0;1;2}*50),10^4))/150),2)
 面值100的充值卡计算公式为:
 
 =INT(MOD(MIN(MOD(A2-{0;1;2}*50*(A2>={0;1;2}*50),30)*10^6+{0;1;2}),10^4)/2)
 面值50的充值卡计算公式为:
 
 =MOD(MOD(MIN(MOD(A2-{0;1;2}*50*(A2>={0;1;2}*50),30)*10^6+{0;1;2}),10^4),2)
 面值30的充值卡计算公式为:
 
 =INT(MOD((A2-MOD(MIN(MOD(A2-{0;1;2}*50*(A2>={0;1;2}*50),30)*10^6+{0;1;2}*50),10^4)),150)/30)
 余额的计算公式为
 
 =MIN(MOD(A2-{0;1;2}*50*(A2>={0;1;2}*50),30))
 
 方法二(由chrisfang版主提供):
 面值300的充值卡计算公式为:
 
 =INT((A2-E2*50-F2*30-D2*100-C2*150)/300)
 面值150的充值卡计算公式为:
 
 =MOD(INT((A2-E2*50-F2*30-D2*100)/150),2)
 面值100的充值卡计算公式为:
 
 =RIGHT(MIN(MOD(TEXT(A2-E2*50-F2*30-100*{0;1;2},"0.00;149"),150)*10^4+{0;1;2}))
 面值50的充值卡计算公式为:
 
 =RIGHT(MIN(MOD(TEXT(A2-50*{0;1},"0.00;29"),30)*10^4+{0;1}))
 面值30的充值卡计算公式为:
 
 =RIGHT(MIN(MOD(TEXT(A2-30*{0;1;2;3;4},"0.00;49"),50)*10^4+{0;1;2;3;4}))
 余额的计算公式为
 
 =A2-SUM((B2:F2*{300,150,100,50,30}))
 
 方法三——VBA算法(由chrisfang版主提供):
 
 Sub test()
nrow = 2
mode = InputBox("使用100元替代150元与50元的组合(1),否(2)", "模式选择", 1)
Do While Range("A" & nrow) <> ""
number = Range("A" & nrow).Value
Range("i" & nrow) = "'" & fenpei(number, mode)
nrow = nrow + 1
Loop
End Sub
Function fenpei(number, mode) As String
Dim temp(1 To 5)
maxnum = 0
mincount = Int(number / 30) + 1
For i300 = 0 To Int(number / 300)
For i150 = 0 To 1
For i100 = 0 To 2
For i50 = 0 To 1
For i30 = 0 To 4
s = i30 * 30 + i50 * 50 + i100 * 100 + i150 * 150 + i300 * 300
scount = i30 + i50 + i100 + i150 + i300
If s <= number And s >= maxnum Then
  If s = maxnum And scount <= mincount Then
     mincount = scount
  Else
    maxnum = s
  End If
  temp(1) = i300
  temp(2) = i150
  temp(3) = i100
  temp(4) = i50
  temp(5) = i30
End If
Next i30
Next i50
Next i100
Next i150
Next i300
If mode = 2 And temp(2) & temp(3) & temp(4) = "020" Then
 fenpei = temp(1) & "101" & temp(5)
Else
If mode = 1 And temp(2) & temp(3) & temp(4) = "101" Then
 fenpei = temp(1) & "020" & temp(5)
Else
 fenpei = temp(1) & temp(2) & temp(3) & temp(4) & temp(5)
End If
End If
End Function
 | 
| 2楼 rongjun
 | 方法一的思路解析: 因为300、150、100是50或30的倍数,所以可以将总金额拆分成这样:
 总金额=30*A+50*B+余额
 其中A、B为整数;
 根据数学知识,整数B可以表示为B=3*C+Y,其中C为整数,Y的取值为{0;1;2},所以:
 总金额=30*A+50*(3*C+Y)+余额
 化简为:
 总金额=30*(A+5*C)+50*Y+余额
 再化简:
 总金额=30*X+50*Y+余额
 其中X为整数,Y为0或1或2
 所以根据余额最小的原则,用如下公式求出最小余额:
 MIN(MOD(总金额-{0;1;2}*50,30))
 考虑到有可能出现负数而产生错误值,所以加个限制条件(总金额>={0;1;2}*50)
 得出求最小余额的公式:
 MIN(MOD(总金额-{0;1;2}*50*(总金额>={0;1;2}*50),30))
 利用加权法求得Y值:
 MOD(MIN(MOD(总金额-{0;1;2}*50*(总金额>={0;1;2}*50),30)*10^6+{0;1;2}),10^4)
 利用加权法求得X值:
 
 =INT((总金额-MOD(MIN(MOD(总金额-{0;1;2}*50*(总金额>={0;1;2}*50),30)*10^6+{0;1;2}*50),10^4))/30)
 然后将X值瓜分:每10张30元面值换成1张300元面值,余下每5张30元面值换成1张150元面值,余下为30元面值的数量。
 将Y值瓜分:每2张50元面值换成1张100元面值,余下为50元面值的数量。
 假设总金额位于A2单元格,即得出公式如下:
 
 300元面值充值卡数量=INT((A2-MOD(MIN(MOD(A2-{0;1;2}*50*(A2>={0;1;2}*50),30)*10^6+{0;1;2}*50),10^4))/300)
150元面值充值卡数量=MOD(INT((A2-MOD(MIN(MOD(A2-{0;1;2}*50*(A2>={0;1;2}*50),30)*10^6+{0;1;2}*50),10^4))/150),2)
30元面值充值卡数量=INT(MOD((A2-MOD(MIN(MOD(A2-{0;1;2}*50*(A2>={0;1;2}*50),30)*10^6+{0;1;2}*50),10^4)),150)/30)
100元面值充值卡数量=INT(MOD(MIN(MOD(A2-{0;1;2}*50*(A2>={0;1;2}*50),30)*10^6+{0;1;2}),10^4)/2)
50元面值充值卡数量=MOD(MOD(MIN(MOD(A2-{0;1;2}*50*(A2>={0;1;2}*50),30)*10^6+{0;1;2}),10^4),2)
 | 
| 3楼 rongjun
 | 方法二的思路解析: 总金额可以用如下数学表达式表示(其中A、B为整数):
 
 总金额=30*A+50*B+余额
 由此可以得出余数计算式:
 
 余额=总金额-50*B-30*A=MOD(总金额-50*B,30)
 其中的B,理论上可以为0~INT(总金额/50),但实际上由于两张50元就可以换成一张100元的,所以B的区间可以设为{0;1}。
 由此可以得到最小余额的表达式为:
 
 =MIN(MOD(总金额-50*{0;1},30))
 考虑到“总金额-50*{0;1}”可能出现负数情况,利用TEXT函数将负数转化为最大余数,达到除错的目的,因此最小余额表达式可以转化为:
 
 =MIN(MOD(TEXT(总金额-50*{0;1},"0.00;29"),30))
 利用加权法可以得出50元面值充值卡数量的计算式为:
 
 =RIGHT(MIN(MOD(TEXT(总金额-50*{0;1},"0.00;29"),30)*10^4+{0;1}))
 同理,余额的表达式也可以表示为:
 
 余额=总金额-50*B-30*A=mod(总金额-30*A,50)
 其中的A,理论上可以为0~INT(总金额/30),但实际上由于5张30元就可以换成一张150元的,所以A的区间可以设为{0;1;2;3;4}。同样使用TEXT函数除错,利用加权法可以得出30元面值充值卡数量的计算式为:
 
 =RIGHT(MIN(MOD(TEXT(总金额-30*{0;1;2;3;4},"0.00;49"),50)*10^4+{0;1;2;3;4}))
 扣除30元和50元面值的金额后,采用同样的算法可以得出100元面值充值卡数量的计算式为:
 
 =RIGHT(MIN(MOD(TEXT(总金额-50元面值金额-30元面值金额-100*{0;1;2},"0.00;149"),150)*10^4+{0;1;2}))
 由于2张150元面值可以换成300元,因此只需将总金额扣除30元、50元、100元面值金额后除以150取整,再对2求余,即可得出150元面值充值卡的数量:
 
 =MOD(INT((A2-E2*50-F2*30-D2*100)/150),2)
 最后,将总金额扣除30元、50元、100元、150元面值的金额,再除以300,取整,即可得出300元面值充值卡的数量:
 
 =INT((A2-E2*50-F2*30-D2*100-C2*150)/300)
 | 
| 4楼 rongjun
 | 附件: 
 
  金额分配(方法一).rar 
 
 
  金额分配(方法二).rar 
 
 
  金额分配(VBA法).rar 
 | 
| 5楼 落雪绽菊
 | 用规划求解可以得到 | 
| 6楼 icenotcool
 |  
   | 
| 7楼 E林好汉
 |  
   | 
| 8楼 lrlxxqxa
 | 好帖 
   |