集合分区问题

本文根据PuLP文档翻译而来,原文请参考
https://pythonhosted.org/PuLP/CaseStudies/a_set_partitioning_problem.html

集合分区问题


集合分区问题确定如何将一个集合(S)中的项目划分为更小的子集。S中的所有项目必须包含在一个且仅包含一个分区中。相关问题是:

  • 集合分包- 所有项目必须包含在零个或一个分区中;
  • 集合覆盖 - 所有项目必须至少包含在一个分区中。

在这个案例研究中,婚礼策划师必须确定婚礼的客人座位分配。为了模拟这个问题,桌子被建模为分区,邀请参加婚礼的嘉宾被建模为S的元素。婚礼策划者希望最大化所有桌子的总幸福感。
这里写图片描述

可以通过显式枚举每个可能的子集来建模集合划分问题。虽然这种方法确实变得难以处理大量项目(不使用列生成),但它确实具有以下优点:分区的目标函数系数可以是非线性表达式(如幸福),并且仍然可以解决此问题使用线性编程。

首先,我们使用allcombinations()生成所有可能的桌座位列表。

#create list of all possible tables
possible_tables = [tuple(c) for c in pulp.allcombinations(guests, max_table_size)]

然后我们创建一个二进制变量,如果表将在解决方案中将为1,否则为零。

#create a binary variable to state that a table setting is used
x = pulp.LpVariable.dicts('table', possible_tables, 
                            lowBound = 0,
                            upBound = 1,
                            cat = pulp.LpInteger)

我们创造LpProblem然后制作目标函数。请注意,此脚本中使用的幸福函数很难以任何其他方式进行建模。

seating_model = pulp.LpProblem("Wedding Seating Model", pulp.LpMinimize)

seating_model += sum([happiness(table) * x[table] for table in possible_tables])

我们指定解决方案中允许的表总数

#specify the maximum number of tables
seating_model += sum([x[table] for table in possible_tables]) <= max_tables, \

这组约束通过保证将guest虚拟机分配给一个表来定义集合分区问题。

#A guest must seated at one and only one table
for guest in guests:
    seating_model += sum([x[table] for table in possible_tables
                                if guest in table]) == 1, "Must_seat_%s"%guest

完整的文件可以在这里找到wedding.py

"""
A set partitioning model of a wedding seating problem

Authors: Stuart Mitchell 2009
"""

import pulp

max_tables = 5
max_table_size = 4
guests = 'A B C D E F G I J K L M N O P Q R'.split()

def happiness(table):
    """
    Find the happiness of the table
    - by calculating the maximum distance between the letters
    """
    return abs(ord(table[0]) - ord(table[-1]))

#create list of all possible tables
possible_tables = [tuple(c) for c in pulp.allcombinations(guests, 
                                        max_table_size)]

#create a binary variable to state that a table setting is used
x = pulp.LpVariable.dicts('table', possible_tables, 
                            lowBound = 0,
                            upBound = 1,
                            cat = pulp.LpInteger)

seating_model = pulp.LpProblem("Wedding Seating Model", pulp.LpMinimize)

seating_model += sum([happiness(table) * x[table] for table in possible_tables])

#specify the maximum number of tables
seating_model += sum([x[table] for table in possible_tables]) <= max_tables, \
                            "Maximum_number_of_tables"

#A guest must seated at one and only one table
for guest in guests:
    seating_model += sum([x[table] for table in possible_tables
                                if guest in table]) == 1, "Must_seat_%s"%guest

seating_model.solve()

print("The choosen tables are out of a total of %s:"%len(possible_tables))
for table in possible_tables:
    if x[table].value() == 1.0:
        print(table)

猜你喜欢

转载自blog.csdn.net/frone/article/details/81452150