Skip to content

示例 8:生产问题

问题描述

有一些设备与一些产品,每个产品有收益,每个设备有数量,生产每个产品会消耗每个设备一定工时。

产品 A产品 B产品 C产品 D产品 E
价值12394105132118
设备 A设备 B设备 C设备 D
数量121486
产品 A产品 B产品 C产品 D产品 E
设备 A0.23h0.44h0.17h0.08h0.36h
设备 B0.13h0.20h0.37h0.19h
设备 C0.25h0.34h0.18h
设备 D0.55h0.72h0.61h

给出每个产品的产量,令总收益最大,并满足以下条件:

  1. 每个设备的工时小于 2000h

数学模型

变量

xp :产品 p 的产量。

中间值

1. 总收益

Profit=pPProfitpxp

2. 设备总工时

ManHourse=pPCostepxp,eE

目标函数

1. 总收益最大

maxProfit

约束

1. 设备工时不能超过最大值

s.t.ManHourseAmounteManHoursMax,eE

期望结果

产品 A 生产 0 个,产品 B 生产 0 个,产品 C 选择 18771 个,产品 D 生产 19672 个,产品 E 生产 53431 个。

代码实现

kotlin
data class Product(
    val profit: Flt64
) : AutoIndexed(Product::class)

data class Equipment(
    val amount: UInt64,
    val manHours: Map<Product, Flt64>
) : AutoIndexed(Equipment::class)

private val maxManHours = Flt64(2000)
private val products: List<Product> = ... // 产品列表
private val equipments: List<Equipment> = ... // 设备列表

// 创建模型实例
val metaModel = LinearMetaModel("demo8")

// 定义变量
val x = UIntVariable1("x", Shape1(products.size))
for (p in products) {
    x[p].name = "${x.name}_${p.index}"
}
metaModel.add(x)

// 定义中间值
val profit = LinearExpressionSymbol(sum(products.map { p ->
    p.profit * x[p]
}), "profit")
metaModel.add(profit)

val manHours = LinearIntermediateSymbols1(
    "man_hours",
    Shape1(equipments.size)
) { i, _ ->
    val e = equipments[i]
    LinearExpressionSymbol(
        sum(products.mapNotNull { p -> e.manHours[p]?.let { it * x[p] } }),
        "man_hours_${e.index}"
    )
}
metaModel.add(manHours)

// 定义目标函数
metaModel.maximize(profit, "profit")

// 定义约束
for (e in equipments) {
    metaModel.addConstraint(
        manHours[e] leq e.amount.toFlt64() * maxManHours,
        "eq_man_hours_${e.index}"
    )
}

// 调用求解器求解
val solver = ScipLinearSolver()
when (val ret = solver(metaModel)) {
    is Ok -> {
        metaModel.tokens.setSolution(ret.value.solution)
    }

    is Failed -> {}
}

// 解析结果
val solution = HashMap<Product, UInt64>()
for (token in metaModel.tokens.tokens) {
    if (token.result!! neq Flt64.one && token.variable.belongsTo(x)) {
        solution[products[token.variable.vectorView[0]]] = token.result!!.round().toUInt64()
    }
}

完整实现请参考: