使用场景
- 有一些报销额度,需要用自己发票的金额去抵扣;
- 如果发票金额总和超过报销额度,只能报销最大额度的金额;
比如:报销额度1000,发票金额1200,那么可以报销1000 - 现在的发票也可以留给下次报,所以你需要凑出符合额度的发票,但不想让金额超出太多;
- 此程序效率低,但你的时间比CPU的时间值钱很多。
效果

Yaodo·2021-04-29·508 次阅读

from itertools import combinations
intro = """====================================
===@凑发票计算器
===@Yaodo
===@https://www.imtrq.com
====================================
"""
print(intro)
s = input("输入现有的每张发票金额,以空格键分隔,按回车键结束:\n")
target = float(input("输入目标金额,按回车键结束:\n"))
li = [float(x) for x in s.split()]
# 最多需要多少张发票
def get_max_num(li, target):
li.sort()
for n in range(1, len(li)+1):
if sum(li[:n]) >= target:
return n
return 0
# 最少需要多少张发票
def get_min_num(li, target):
li.sort(reverse=True)
for n in range(1, len(li)+1):
if sum(li[:n]) >= target:
return n
return 0
# 如果选择n张发票,返回金额最接近的组合
def try_a_num(n, li, target):
comb = list(combinations(li, n))
answer = []
for i in comb:
if sum(i)>=target:
answer.append((sum(i), len(i), i))
if len(answer)==0:
return (0,0,0)
else:
answer.sort()
return answer[0]
# 每个n试一次
def work(li, target):
max_num = get_max_num(li, target)
min_num = get_min_num(li, target)
if max_num*min_num==0:
return 0
answer = []
for n in range(min_num, max_num+1):
answer.append(try_a_num(n, li, target))
return answer
# 输出结果
answer = work(li, target)
if answer==0 or answer==[]:
print("错误!无法凑出所需金额。")
else:
print("\n====================================\n方案列表\n====================================")
answer.sort()
i = 1
for x in answer:
output = '{}\t总金额:{:.2f}\t发票张数:{}\t组合:{}'.format(i, x[0], x[1], x[2])
print(output)
i+=1
Comments | 1 条评论
哈哈!好有趣!