python回溯算法(组合相加等于某值的所有组合)应用2.0

from decimal import Decimal
"""
需求:多个订单认款多笔流水
第一步:找出每一笔流水中每个可能的组合
第二步:循环所有的可能的组合,用字典相加和目标匹配,保证不重复覆盖所有的订单和所有的流水
第三步:最后输出所有的可能组合直接把所有的流水和订单匹配完成
"""

# 递归函数,返回 arr 中找出 sum 值为 target 的组合及它们的索引
def find_combinations(arr, target):
    # 如果 target 是单个值,则将其转化为单元素列表
    if isinstance(target, (int, float)):
        target = [Decimal(str(target))]

        # 递归函数,返回 arr 中找出 sum 值为 target 的组合及它们的索引
    i = 0

    def helper(arr, index, target, res, path):
        if target == 0:
            # 创建一个新的字典,其中键是索引,值是元素值
            comb_dict = {i: arr[i] for i in path}
            res.append(comb_dict)
            return
        if target < 0 or index >= len(arr):
            return
        num = arr[index]
        if isinstance(num, (int, float)):
            num = Decimal(str(num))
            # 递归调用,包含当前元素
        helper(arr, index + 1, target - num, res, path + [index])
        # 递归调用,不包含当前元素
        helper(arr, index + 1, target, res, path)

    result = {}
    for t in target:
        res = []
        helper(arr, 0, Decimal(str(t)), res, [])
        # 将结果存储到字典中,键是目标值,值是组合的字典列表
        i += 1
        result[str(float(t)) + '-' + str(i)] = res
    return result


# 获取到所有可能的组合之后,再次获取组合结果中最后能包含arr所有的值和target中的所有的值

def find_combinations_with_sources(lists, target_dict):
    def backtrack(index, current_combination, path, result):
        if index == len(lists):
            if current_combination == target_dict:
                # 构建包含来源信息的最终结果
                final_combination = {
                    k: (v, f"list{d[0]}")
                    for d in path
                    for k, v in d[1].items()
                }
                result.append(final_combination)
            return

        for i, dict_item in enumerate(lists[index]):
            new_path = path + [(index + 1, dict_item)]  # 确保列表索引从1开始
            new_combination = current_combination.copy()
            if not set(dict_item.keys()) & set(current_combination.keys()):
                new_combination.update(dict_item)
                backtrack(index + 1, new_combination, new_path, result)

    result = []
    backtrack(0, {}, [], result)
    return result


arr = [42.9, 257.6, 550, 1200, 2302, 2302, 88.8, 6182.8, 480, 147, 2220, 798, 237.8, 40805, 45654.4, 282, 9982.5, 448,
       788, 3097, 9472, 200, 970, 327]

target = [37950.6, 90884.2]
res = find_combinations(arr, target)
print("res===============", res)

listall = []
for value in res.values():
    listall.append(value)
print("listall=================", listall)
# for k in sorted(res.keys()):
#     print("{}: {}".format(k, res[k]))

target_dict = {index: value for index, value in enumerate(arr)}

# 调用函数并打印结果
combinations = find_combinations_with_sources(listall, target_dict)
for combination in combinations:
    source_info = combination.values()
    group_by_list = {}
    for value, source in source_info:
        if source not in group_by_list:
            group_by_list[source] = []
        group_by_list[source].append(value)

    for source, values in group_by_list.items():
        print(f"{source}: {values}")

    print("\n---\n")

注:用了两次回溯算法,大家有好的方法请帮忙指正,目前的方法也会有些固有的缺陷

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值