1. 程式人生 > 實用技巧 >Pulp之四:官網上的應用樣例-A Set Partitioning Problem (集合劃分問題)

Pulp之四:官網上的應用樣例-A Set Partitioning Problem (集合劃分問題)

以下例子來源於PULP的官方文件,本例中使用了pulp.allcombinations()方法,

allcombinations(list, k): 返回list的所有元素組合,元素個數不超過k

A set partitioning problem determines how the items in one set (S) can be partitioned into smaller subsets.
All items in S must be contained in one and only one partition.

Related problems are (不同的例子):
1 set packing (集合配置)- all items must be contained in zero or one partitions; 所有專案必須屬於某集合或不屬於任何集合。
2 set covering (集合覆蓋) - all items must be contained in at least one partition.

問題:
有17個客人,有5張桌子,每張桌子最多坐4人。如何分配才能坐滿?
如婚禮座位分配問題,一個客人(item)至少坐在某一桌(partition),不能同時在兩桌,一桌可以有多個客人。
In this case study a wedding planner must determine guest seating allocations for a wedding. To model this problem the tables are modelled as the partitions and the guests invited to the wedding are modelled as the elements of S. The wedding planner wishes to maximise the total happiness of all of the tables.

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()      # 結果是: ['A', 'B', 'C', 'D', 'E', 'F'... 'R']
# guest1 = 'ABC GHI'.split()    這樣分割的結果是 ['ABC', 'GHI']

def happiness(table):
    return abs(ord(table[0]) - ord(table[-1]))
""
    Find the happiness of the table
    - by calculating the maximum distance between the letters
    ord() 函式是 chr() 函式(對於8位的ASCII字串)或 unichr() 函式(對於Unicode物件)的配對函式,
    它以一個字元(長度為1的字串)作為引數,返回對應的 ASCII 數值,或者 Unicode 數值
""

                
# 列表化所有的方案
possible_tables = [tuple(c) for c in pulp.allcombinations(guests, max_table_size)]

# 設定變數,這次是一個整數規劃的問題,引入01決策變數,在線性規劃中設定01變數即,把決策變數的上下限變為01,並設定為整數
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])
# x對應一種方案,a對應效益,各個方案的效益總和即為目標函式
# 效益總和 a1x1 + a2x2 + a3x3 + a4x4

#限定決策變數的總數目
# x1+x2+x3...<= 某個值
seating_model += sum([x[table] for table in possible_tables]) <= max_tables,  "Maximum_number_of_tables"                  

# 每個客人只能出席一桌
# 這個語句需要留意一下
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)