A trading company must assign three sales managers to three sales offices. Its objective is to find the assignments that maximize the total yearly sales of all three offices. Naturally, only one person can be assigned to each sales office. The expected yearly sales (in millions of dollars) if each individual is assigned to each office are as follows:
| Atlanta | Boston | Chicago | |
|---|---|---|---|
| Tardy | 21 | 25 | 17 |
| Vincent | 14 | 17 | 15 |
| Schuldiner | 21 | 19 | 13 |
The relocation expense budget for all three moves is $200000. The costs (in thousands of dollars) of relocating each individual to each location are as follows:
| Atlanta | Boston | Chicago | |
|---|---|---|---|
| Tardy | 65 | 50 | 30 |
| Vincent | 90 | 65 | 85 |
| Schuldiner | 100 | 20 | 80 |
Formulate and solve an integer programming model allowing you to decide which individual should be assigned to which office.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# File: solve.py
# Author: Jakub Kozłowicz
# Copyright (c) Jakub Kozłowicz 2023
# MIT License
"""File contain code for solving assignment 16.
It uses the following libraries:
- pulp.
"""
import enum
import itertools
import sys
from pulp import LpBinary, LpMaximize, LpProblem, LpVariable, lpSum, value
class SalesOffice(enum.StrEnum):
"""Enum for sales offices."""
ATLANTA = "Atlanta"
BOSTON = "Boston"
CHICAGO = "Chicago"
class SalesManager(enum.StrEnum):
"""Enum for sales managers."""
TARDY = "Tardy"
VINCENT = "Vincent"
SCHULDINER = "Schuldiner"
YEARLY_SALES = {
SalesManager.TARDY: {
SalesOffice.ATLANTA: 21_000_000,
SalesOffice.BOSTON: 25_000_000,
SalesOffice.CHICAGO: 17_000_000,
},
SalesManager.VINCENT: {
SalesOffice.ATLANTA: 14_000_000,
SalesOffice.BOSTON: 17_000_000,
SalesOffice.CHICAGO: 15_000_000,
},
SalesManager.SCHULDINER: {
SalesOffice.ATLANTA: 21_000_000,
SalesOffice.BOSTON: 19_000_000,
SalesOffice.CHICAGO: 13_000_000,
},
}
RELOCATION_COSTS = {
SalesManager.TARDY: {
SalesOffice.ATLANTA: 65_000,
SalesOffice.BOSTON: 50_000,
SalesOffice.CHICAGO: 30_000,
},
SalesManager.VINCENT: {
SalesOffice.ATLANTA: 90_000,
SalesOffice.BOSTON: 65_000,
SalesOffice.CHICAGO: 85_000,
},
SalesManager.SCHULDINER: {
SalesOffice.ATLANTA: 100_000,
SalesOffice.BOSTON: 20_000,
SalesOffice.CHICAGO: 80_000,
},
}
MAX_RELOCATION_COST = 200_000
def main() -> int:
"""Main entry point of the program."""
permutations = list(itertools.product(SalesManager, SalesOffice))
problem = LpProblem("sales_maximization", LpMaximize)
# Decision variables
x = LpVariable.dicts(
"x",
permutations,
0,
1,
LpBinary,
)
# Objective function
problem += lpSum(
[
YEARLY_SALES[manager][office] * x[(manager, office)]
for manager, office in permutations
]
)
# Office Constraints
for i in SalesManager:
problem += lpSum([x[(i, j)] for j in SalesOffice]) == 1
for j in SalesOffice:
problem += lpSum([x[(i, j)] for i in SalesManager]) == 1
# Relocation Constraints
problem += (
lpSum(
[
RELOCATION_COSTS[manager][office] * x[(manager, office)]
for manager, office in permutations
]
)
<= MAX_RELOCATION_COST
)
# Solve the problem
problem.solve()
# Print the results
print(f"Status: {problem.status}")
for variant in permutations:
if x[variant].value() == 1:
manager, office = variant
print(f"{manager} is assigned to {office}")
print(f"Total yearly sales = {value(problem.objective):,}")
return 0
if __name__ == "__main__":
sys.exit(main())