在给定零件价格变动的情况下,每周最大化$整体而

时间:2017-03-13 18:37:58

标签: algorithm

我有一笔金额,我希望最大限度地增加我在为给定项目列表购买的产品上的花费。

例如60美元。我不能每周花费超过60美元,但可以保留任何剩余金额。所以,如果我花58美元,下周我就会花62美元。如果我在第1周购买产品,我可以在第2周使用剩余金额,因此无需重新购买相同的商品。

解决方案需要是通用的,以便在每周固定金额的情况下,我可以在很多产品和许多项目之间实现最大化。

我需要生成一份报告,其中包含要购买的产品列表以及该周要执行的项目列表。价格每周更新一次,因此我需要每周重新计算最大支出(意味着预测不是解决方案的一部分),我需要重新使用已购买产品/库存的金额。

我拥有所有数据,并且没有任何未知变量。我只需要能够弄清楚如何在固定金额的历史记录下最大化购买给定零件和整体的东西。

通过示例使其更具体(尽管从我的真实数据中抽象出来):

我有一个产品数据库(12.5 K不同的产品)及其相应的价格。我还有一个固定列表项目列表(假设2500)我希望这些产品。对于每个项目,我都有相应的产品。每个项目都需要不同数量的产品。项目可以为每个项目提供重叠或独特的产品。

例如:

项目1正在建造我的模型飞机; 项目2正在修复我的相框; 项目3正在建造一个鸟屋; 等

项目1可能需要: 胶水(1oz) 油漆(3夸脱) 香脂木(2磅)

项目2可能需要: 胶水(2盎司) 指甲(10支)

项目3可能需要: 胶水(10盎司) 油漆(5夸脱) 指甲(40支) 木香脂(3磅) 木松(50磅)

产品:

Glue 4oz - 10美元 油漆3qts - 30美元 指甲15计数 - 7美元 Wood Balsam 8磅 - 12美元 木松12磅 - $ 8

例如,如果我以10美元购买一瓶胶水(4盎司),我可以将它用于我的飞机和相框,但不能用于我的鸟屋。由于价格变化(销售/需求/等),我需要每周对所有产品和所有项目进行详尽的分析。

如何才能最好花60美元在一周内完成尽可能多的项目?第2周我花了60美元(很可能有剩余的)钱,并且从前一周剩下的产品(如胶水)?

任何类似或完全类似的python代码/项目我可以根据自己的需要导入和修改吗?

任何有关算法,示例代码,完整解决方案的帮助!?!,想法等都将不胜感激......

提前致谢!!! (仅供参考:他是个人项目。)

2 个答案:

答案 0 :(得分:1)

这是一个非常适合用数学编程解决的问题。通过数学优化,您可以优化变量(例如,变量表示项目是否在某个点进行),其目标类似于所执行项目的数量,同时还要考虑一组约束。对于Python,有几个免费库可用于优化数学程序,我将展示如何使用PuLP开始解决您的问题。请注意,针对这类问题的免费软件通常比商用软件更差,这可能非常昂贵。对于小问题或简单问题,自由软件就足够了。

开始使用:

easy_install pulp

现在,进口纸浆和一点帮助itertools.product。有很多方法可以表示您的数据,我选择声明一些作为索引集的范围。所以r = 0将是胶水,而p = 0则构建模型飞机。您必须选择的时间段数。有4个时间段,所有项目最终都可以进行。

from pulp import *
from itertools import product

R = range(5) # Resources
P = range(3) # Projects
T = range(4) # Periods

您的参数可以表示如下。 project_consumption [0,0]表示项目0需要进行材料0(胶水)的1/4。

resource_prices = (10, 30, 7, 12, 8) # Price per unit of resource
# Needed percentage of resource r for project p
project_consumption = {(0, 0): 1/4, (0, 1): 3/3, (0, 2): 0/15, (0, 3): 2/8, (0, 4): 0/12,
                      (1, 0): 2/4, (1, 1): 0/3, (1, 2): 10/15, (1, 3): 0/8, (1, 4): 0/12,
                      (2, 0): 10/4, (2, 1): 5/3, (2, 2): 40/15, (2, 3): 3/8, (2, 4): 50/12,}
budget = 60

接下来,我们宣布我们的问题表述。我们希望最大化项目数量,因此我们声明了LpMaximize的意义。决策变量接下来声明:

  • planned_project [p,t]:如果项目p在期间t中进行,则为1,否则为0
  • stocked_material [r,t]:t
  • 中库存的物料r的数量
  • consumption_material [r,t]:在时段t中消耗的r的数量
  • purchase_material [r,t]:在t
  • 中购买的r的数量
  • 预算[t]:资金余额t

宣布我们的问题:

m = LpProblem("Project planning", LpMaximize)

planned_project = LpVariable.dicts('pp', product(P, T), lowBound = 0, upBound = 1, cat = LpInteger)
stocked_material = LpVariable.dicts('ms', product(R, T), lowBound = 0)
consumption_material = LpVariable.dicts('cm', product(R, T), lowBound = 0)
purchase_material = LpVariable.dicts('pm', product(R, T), lowBound = 0, cat = LpInteger)
budget = LpVariable.dicts('b', T, lowBound = 0)

我们的目标是如下问题。我将每个变量乘以(len(T) - t),这意味着项目的价值更早,而不是更晚。

m += lpSum((len(T) - t) * planned_project[p, t] for p in P for t in T)

现在我们可以通过添加必要的约束来限制决策变量的值。第一个约束条件将我们的材料库存限制为购买和消耗的材料的差异。

for r in R:
    for t in T:
        if t != 0:
            m += stocked_material[r, t] == stocked_material[r, t-1] + purchase_material[r, t] - consumption_material[r, t]
        else:
            m += stocked_material[r, t] == 0 + purchase_material[r, 0] - consumption_material[r, 0]

第二个约束确保每个时期内进行的项目消耗的材料数量正确。

for r in R:
    for t in T:
        m += lpSum([project_consumption[p, r] * planned_project[p, t] for p in P]) <= consumption_material[r, t]

第三个限制条件确保我们不会花费超过预算,此外剩余金额可用于未来期间。

for t in T:
    if t > 0:
        m += budget[t] == budget[t-1] + 60 - lpSum([resource_prices[r] * purchase_material[r, t] for r in R])
    else:
        m += budget[0] == 60 - lpSum([resource_prices[r] * purchase_material[r, 0] for r in R])

最后,每个项目只能进行一次。

for p in P:
    m += lpSum([planned_project[p, t] for t in T]) <= 1

我们可以通过调用:

来优化我们的问题
m.solve()

优化后,我们可以使用.value()方法访问每个最佳决策变量值。打印有关我们最佳行动计划的一些有用信息:

for (p, t), var in planned_project.items():
    if var.value() == 1:
        print("Project {} is conducted in period {}".format(p, t))

for t, var in budget.items():
    print("At time {} we have a balance of {} $".format(t, var.value()))

for (r, t), var in purchase_material.items():
    if var.value() > 0:
        print("At time {}, we purchase {} of material {}.".format(t, var.value(), r))

输出:

Project 0 is conducted in period 0
Project 2 is conducted in period 3
Project 1 is conducted in period 0
At time 0 we have a balance of 1.0 $
At time 1 we have a balance of 1.0 $
At time 2 we have a balance of 61.0 $
At time 3 we have a balance of 0.0 $
At time 0, we purchase 1.0 of material 0.
At time 3, we purchase 1.0 of material 3.
At time 0, we purchase 1.0 of material 3.
At time 1, we purchase 2.0 of material 1.
At time 0, we purchase 1.0 of material 2.
At time 3, we purchase 3.0 of material 2.
At time 3, we purchase 6.0 of material 4.
At time 0, we purchase 1.0 of material 1.
At time 3, we purchase 4.0 of material 0.

请注意,在解决方案中,我们在时间3购买了6个单位的材料4(6 * 12木松)。我们从未真正使用过那么多,但解决方案仍然被认为是最佳的,因为我们的目标并没有预算如果我们购买更多或更少,我们可以做的项目数量不会影响。因此有多种最佳解决方案。作为多标准优化问题,您可以使用Big-M值来最小化目标中的预算利用率。 我希望这能帮助你解决问题。您可以在互联网上找到无数的数学编程资源和示例。

答案 1 :(得分:0)

这样的事情可以起作用,为每个项目创建材料列表,项目列表和价格字典。每次调用compareAll()都会显示列表中最便宜的项目。您还可以添加一个循环,从列表中删除最便宜的项目,并在每次运行时将其添加到待办事项列表中,以便下一次运行找到下一个最便宜的项目。

p1 = ["glue","wood","nails"]
p2 = ["screws","wood"]
p3 = ["screws","wood","glue","nails"]
projects = [p1,p2,p3]
prices = {"glue":1,"wood":4,"nails":2,"screws":1}
def check(project,prices):
     for i in project:
        iPrice = 0
        projectTotal = 0
        total = 0
        for n in prices:
            if(i == n):
                iPrice = prices[n]
        total = total + iPrice
    print("Total: " + str(total))
    return total

def compareAll(projectList):
best = 100 #Or some other number which exceeds your budget
for i in projectList:
    if (check(i,prices) < best):
        best = check(i,prices)