二维背包动态规划问题——两个约束

该博客记录了一个优化问题,涉及如何在多个区域中调度快递小哥进行收派件任务,以最小化总成本。每个小哥有收派件量上限和保底成本,未完成的件会有惩罚。问题被类比为二维背包问题,使用动态规划求解单个区域的最优调度。博客中展示了Python代码实现,通过读取小哥和区域数据,计算并输出每个区域的小哥分配方案及对应的总成本。
摘要由CSDN通过智能技术生成

问题需求:跟定多个区域,一个区域拥有固定的收派件量,需要分配小哥进行收派,每个小哥有收派量上限,以及保底成本,当一个区域的收派量没有全部完成,剩余的件会有相应的惩罚成本

目标:调度使成本最小

由于涉及三维度的优化问题,此篇主要记录单个区域调度最优情况,类比二维背包问题,两个约束,dp初始化为成本最大值,放入小哥的value为小哥的节约成本,并打印出分配结果。

import pandas as pd
import json
import gc

df_xiaoge = pd.read_csv("./小哥列表.csv", sep=',')
df_xiaoge["小哥id"] = df_xiaoge["小哥id"].apply(lambda x: int(x.split('_')[1]))
df_xiaoge.sort_values(by="单位派件成本")

# df_zone = pd.read_csv("./compet_total_zone.csv", sep=',')
df_zone = pd.read_csv("./pred__.csv", sep=',')
df_zone["zone_id"] = df_zone["zone_id"].apply(lambda x: int(x.split("_")[1]))
df_zone["date_str"] = df_zone["date_str"].apply(lambda x: int(x[0:4]+x[5:7]+x[8:10]))
# shuffsg
dict_date = {}
date_list = [20200829, 20200830, 20200831]

for dd in date_list:
    stuffs = df_xiaoge[["收件能力", "派件能力", "节约成本", "小哥id","保底收入"]].values.tolist()
    # stuffs.insert(0, [0, 0, 0, -1])
    df = ((df_zone[df_zone["date_str"] == dd]).sort_values(by="zone_id")).astype("int")
    # df["sum"] = df["pai_num"] + df["shou_num"]
    # df = df.sort_values(by="sum", ascending=False)

    zone_pai = list(df["pai_num"])
    zone_shou = list(df["shou_num"])

    sum_cost = 0
    dict_xiaoge = {}
    print(dd)
    # for z in range(len(zone_pai)):
    for z in range(30):
        pai_most = zone_pai[z]
        shou_most = zone_shou[z]
        zz = df.iloc[z, :]["zone_id"]
        dp = [[[(pai_most * 12 + shou_most * 18) * (-1) for _ in range(pai_most + 1)] for _ in range(shou_most + 1)] for
              _ in range(len(stuffs)+1)]
        ans_mid = [[[(-1, 0, 0, 0) for _ in range(pai_most + 1)] for _ in range(shou_most + 1)] for
              _ in range(len(stuffs)+1)]
        for i in range(1, len(dp)):
            for j in range(len(dp[0])):
                for k in range(len(dp[0][0])):
                    v_i = min(stuffs[i-1][0], j)
                    weight_i = min(stuffs[i-1][1], k)
                    w_i = 17*v_i + 11*weight_i - stuffs[i-1][4]
                    if dp[i - 1][j - v_i][k - weight_i] + w_i > dp[i - 1][j][k]:
                        dp[i][j][k] = dp[i - 1][j - v_i][k - weight_i] + w_i
                        ans_mid[i][j][k] = (i-1, v_i, weight_i, w_i)
                    else:
                        dp[i][j][k] = dp[i - 1][j][k]
                        ans_mid[i][j][k] = (i-1, 0, 0, 0)
        print("index:", z)
        print("zone:", zz)
        print("最小成本:", -1 * dp[-1][-1][-1])
        j = shou_most
        k = pai_most
        ans = []
        for i in range(len(stuffs), 0, -1):
            x, y, z, w = ans_mid[i][j][k]
            while (j - y >= 0 and k - z >= 0):
                if dp[i-1][j - y][k - z] + w > dp[i-1][j][k]:
                    j -= y
                    k -= z
                    ans.append(stuffs[x][3])
                    break
                else:
                    break

        ans_ = ["id_" + str(x) for x in ans]
        zone_name = "zone_%s" % zz
        dict_xiaoge[zone_name] = ans_
        print("小哥id:", ans_)
        cost = 0
        real_shou = 0
        real_pai = 0
        for i in ans:
            tmp = (df_xiaoge[df_xiaoge["小哥id"] == i].values).tolist()[0]
            cost += tmp[1] + tmp[2] + tmp[3]
            real_shou += tmp[1]
            real_pai += tmp[2]
        if (real_shou > shou_most):
            cost += (shou_most - real_shou)
        else:
            cost += 18*(shou_most - real_shou)
        if (real_pai > pai_most):
            cost += (pai_most - real_pai)
        else:
            cost += 12*(pai_most - real_pai)
        print("重新计算成本:", cost)
        sum_cost += cost
        #         break
        t = stuffs
        stuffs = []
        for l in t:
            if l[3] in ans:
                continue
            stuffs.append(l)
        print()
        del dp, ans_mid
        gc.collect()
    print(dd, "总成本:", sum_cost)
    dd_ = str(dd)[0:4]+"-"+str(dd)[4:6]+"-"+str(dd)[6:8]
    dict_date[dd_] = dict_xiaoge
    print()
    print()
json_ans = json.dumps(dict_date)
with open('./sche.json', 'w') as json_file:
    json_file.write(json_ans)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值