Добавил:
я зроблений з цукру Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
7
Добавлен:
09.12.2023
Размер:
5.2 Кб
Скачать
import pandas as pd
from tabulate import tabulate
from cvxopt import matrix, glpk


def print_constraints(constraints, constr_names, var_names):
    '''Выводит левую часть матрицы ограничений в виде таблицы.'''
    data = dict(zip(constr_names, constraints))
    df = pd.DataFrame(data, index=var_names)
    print(tabulate(df, headers='keys', tablefmt='psql'))


# Переменные
# Кол-во постоянных работников:
# x1-7 - пон-воскр, утренняя смена;
# x8-14 - пон-воскр, вечерняя смена.

# Кол-во почасовых рабочих:
# y1-7 - пон-воскр, первая четверть рабочего дня;
# y8-14 - пон-воскр, вторая;
# y15-21 - третья;
# y22-28 - четвертая.

CONSTRAINT_COUNT = 70
X_COUNT = 14
Y_COUNT = 28
VAR_COUNT = 42
WORKER_SALARY = 54400
FREELANCER_SALARY = 6720

# Задача минимазации - знак переменных не меняется.
c = [WORKER_SALARY] * X_COUNT
c.extend([FREELANCER_SALARY] * Y_COUNT)

G = []
# Условия на занятость в течение недели.
# k - смена: утренняя или вечерняя.
for s in range(2):
    # i - день недели.
    for i in range(7):
        constraint = [0] * VAR_COUNT
        # Ставим 1 на месте постоянных рабочих:
        # j + 3 - дни, в которые заступили рабочие, которые будут
        # работать в i день;
        # 7 * s - учитывает смену.
        for j in range(5):
            constraint[(i + j + 3) % 7 + 7 * s] = -1  # Ограничение снизу

        # Теперь на месте временных.
        one_quart = constraint.copy()
        # Одно условие: почасовой рабочий выходит в одну четверть.
        one_quart[X_COUNT * (s + 1) + i] = -1
        G.append(one_quart)

        # Второе условие: почасовой рабочий выходит в другую четверть.
        second_quart = constraint.copy()
        second_quart[X_COUNT * (s + 1) + i + 7] = -1
        G.append(second_quart)

# Условия на неотрицательность количества рабочих.
for i in range(VAR_COUNT):
    constraint = [0] * VAR_COUNT
    constraint[i] = -1  # Ограничение снизу
    G.append(constraint)


# Вывод матрицы ограничений неравенств.
weekdays = ["пн", "вт", "ср", "чт", "пт", "сб", "вс"]
times = ['7-11', '11-15', '15-19', '19-23']
shift = ['у', 'в']
column_names = [f"{col}, {time}" for col in weekdays for time in times[:2]]
column_names.extend(
    [f"{col}, {time}" for col in weekdays for time in times[2:]]
)

var_names = [f"x({weekdays[i % 7]}, {shift[i // 7]})" for i in range(X_COUNT)]
var_names.extend(
    [f"y({weekdays[i % 7]}, {times[i // 7]})" for i in range(0, Y_COUNT)]
)

print("Матрица ограничений неравенств:")
print_constraints(G, column_names, var_names)


# Правая часть матрицы ограничений неравенств.
h = [-8, -8, -6, -5, -6, -5, -5, -6, -7, -8, -9, -8, -6, -5,
     -7, -6, -4, -5, -4, -4, -6, -7, -8, -9, -7, -6, -4, -4]
h.extend([0] * VAR_COUNT)


# Проверка на то, что кол-во переменных правильное.
assert(len(c) == VAR_COUNT)
assert(len(G) == CONSTRAINT_COUNT)
assert(len(G[0]) == VAR_COUNT)
assert(len(h) == CONSTRAINT_COUNT)

c = matrix(c, tc='d')
G = matrix(G, tc='d')
h = matrix(h, tc='d')

status, solution = glpk.ilp(c, G.T, h, I=set(range(VAR_COUNT)))

# Вывод результатов и расчет целевой функции.
x_morning = list(map(int, solution[0:X_COUNT - 7]))
x_evening = list(map(int, solution[7:X_COUNT]))

y = [
    list(map(int, solution[X_COUNT + 7*(i - 1):X_COUNT + 7*i]))
    for i in range(1, 5)
]

weekdays = ["пн", "вт", "ср", "чт", "пт", "сб", "вс"]
columns = [[x1, x2] for x1, x2 in zip(x_morning, x_evening)]
print("\nКоличество постоянных работников, заступающих на работу в опр. день:")
print_constraints(columns, constr_names=weekdays, var_names=['утро', 'вечер'])

columns = [[*col] for col in zip(*y)]
print("\nКоличество временных работников по дням и сменам:")
print_constraints(columns, weekdays, ['7-11', '11-15', '15-19', '19-23'])

objective = sum(map(lambda x: x * WORKER_SALARY, solution[0:X_COUNT]))
objective += sum(map(lambda x: x * FREELANCER_SALARY, solution[X_COUNT:]))
print(f"\nЗначение целевой функции: {int(objective)} рублей.")
print(f'Количество постоянных рабочих: {sum(x_morning) + sum(x_evening)} чел.')
print(f'Количество временных рабочих: {sum(map(sum, y))} чел.', )
Соседние файлы в папке Практическая работа №1