这个问题缺乏一个好的模型。目标/损失的不同表述将导致完全不同的行为/解决方案。
这是一种混合整数编程方法(因为您的问题已经是 np-hard):
模型 A
- 第一偏好给出满意 X,第二:Y,... (9, 4, 1, 0) = 平方反比
- 这相当于最小二乘解/l2-范数解(= 较大的失误比较小的失误更难处罚)
- 我们希望最大限度地提高总体满意度
模型效果
代码
import math
import numpy as np
from cvxpy import *
# PROBLEM
# -------
# colors = orange, green, red, blue
n_colors = 4
n_lollies_per_color = 5
n_lollies = n_colors * n_lollies_per_color
prefs = np.asarray([[0, 1, 2, 3],
[1, 3, 2, 0],
[0, 2, 3, 1]])
n_persons = prefs.shape[0]
n_lollies_per_person = n_lollies / n_persons
# SOLVER
# ------
per_person_per_lolly_satisfaction_vector = np.asarray([[n_colors -1 - np.where(prefs[p, :] == c)[0]
for c in range(n_colors)]
for p in range(n_persons)]).reshape((3,4))
# Decision-vars
X = Int(n_persons, n_colors)
# Constraints
constraints = []
# non-zero lollies
constraints.append(X >= 0)
# exactly n_lollies_per_color are distributed
for c in range(n_colors):
constraints.append(sum_entries(X[:,c]) == n_lollies_per_color)
# Objective
objective = Maximize(sum_entries(mul_elemwise(np.square(per_person_per_lolly_satisfaction_vector), X)))
problem = Problem(objective, constraints)
problem.solve(verbose=False)
print(problem.value)
print(np.round(X.value)) # Rows -> persons; Columns -> amount of lollies they got
输出
129.9999999837688
[[ 1. 0. 0. 0.]
[ 0. 5. 0. 5.]
[ 4. 0. 5. 0.]]
观察
- 第一个人只得到 1 个棒棒糖,而其他人得到 9/10(如预期的那样)
型号 B
- 与 A 相同,但我们只允许在每个人之间获得 1 的棒棒糖数量差异 -> 这是硬编码到约束中(更强大的软约束更难实现 ->关键词:凸度)
效果
代码差异
只需添加这些约束:
# lower and upper bound on lollies received -> at most 1 lolly less than everyone else
for p in range(n_persons):
constraints.append(sum_entries(X[p, :]) >= math.floor(n_lollies_per_person))
constraints.append(sum_entries(X[p, :]) <= math.ceil(n_lollies_per_person))
输出
119.99999984107899
[[ 5. 0. 0. 1.]
[-0. 5. 0. 2.]
[ 0. 0. 5. 2.]]
观察