import numpy as np import tkinter as tk from tkinter import messagebox from typing import List, Tuple class TransportProblemApp: def __init__(self, root: tk.Tk) -> None: """ Инициализация приложения. :param root: Основное окно приложения (Tkinter). """ self.root: tk.Tk = root self.root.title("Транспортная задача") self.suppliers: int = 3 self.consumers: int = 3 self.setup_ui() def setup_ui(self) -> None: """ Создание интерфейса приложения, включая поля для ввода данных и кнопки. """ self.frame_controls: tk.Frame = tk.Frame(self.root) self.frame_controls.pack(pady=10) tk.Label(self.frame_controls, text="Количество поставщиков:").grid(row=0, column=0) self.entry_suppliers: tk.Entry = tk.Entry(self.frame_controls, width=5) self.entry_suppliers.insert(0, str(self.suppliers)) self.entry_suppliers.grid(row=0, column=1) tk.Label(self.frame_controls, text="Количество потребителей:").grid(row=0, column=2) self.entry_consumers: tk.Entry = tk.Entry(self.frame_controls, width=5) self.entry_consumers.insert(0, str(self.consumers)) self.entry_consumers.grid(row=0, column=3) tk.Button(self.frame_controls, text="Применить", command=self.update_table).grid(row=0, column=4, padx=10) self.frame_table: tk.Frame = tk.Frame(self.root) self.frame_table.pack(pady=10) self.update_table() self.frame_buttons: tk.Frame = tk.Frame(self.root) self.frame_buttons.pack(pady=10) tk.Button(self.frame_buttons, text="Рассчитать", command=self.solve).pack() def update_table(self) -> None: """ Обновление таблицы для ввода данных о поставщиках, потребителях, запасах и потребностях. """ self.suppliers = int(self.entry_suppliers.get()) self.consumers = int(self.entry_consumers.get()) for widget in self.frame_table.winfo_children(): widget.destroy() self.entries_costs: List[List[tk.Entry]] = [] self.entries_supplies: List[tk.Entry] = [] self.entries_demands: List[tk.Entry] = [] # Заголовок "Пункт назначения" tk.Label(self.frame_table, text="Пункт назначения").grid(row=0, column=1, columnspan=self.consumers) tk.Label(self.frame_table, text="Пункт отправления").grid(row=1, column=0) for j in range(self.consumers): tk.Label(self.frame_table, text=f"B{j+1}").grid(row=1, column=j+1) tk.Label(self.frame_table, text="Запас груза").grid(row=1, column=self.consumers+1) # Данные для поставщиков for i in range(self.suppliers): tk.Label(self.frame_table, text=f"A{i+1}").grid(row=i+2, column=0) row_entries: List[tk.Entry] = [] for j in range(self.consumers): entry: tk.Entry = tk.Entry(self.frame_table, width=5) entry.grid(row=i+2, column=j+1) row_entries.append(entry) self.entries_costs.append(row_entries) entry_supply: tk.Entry = tk.Entry(self.frame_table, width=5) entry_supply.grid(row=i+2, column=self.consumers+1) self.entries_supplies.append(entry_supply) # Данные для потребителей tk.Label(self.frame_table, text="Потребность в грузе").grid(row=self.suppliers+2, column=0) for j in range(self.consumers): entry_demand: tk.Entry = tk.Entry(self.frame_table, width=5) entry_demand.grid(row=self.suppliers+2, column=j+1) self.entries_demands.append(entry_demand) def solve(self) -> None: """ Решение транспортной задачи методом минимальных элементов. Вычисляет и отображает результаты. """ try: supplies: np.ndarray = np.array([int(entry.get()) for entry in self.entries_supplies]) demands: np.ndarray = np.array([int(entry.get()) for entry in self.entries_demands]) costs: np.ndarray = np.array([[int(entry.get()) for entry in row] for row in self.entries_costs], dtype=float) if supplies.sum() != demands.sum(): messagebox.showerror("Ошибка", "Сумма запасов должна равняться сумме потребностей.") return # Создание копии массива для расчета итоговой стоимости original_costs: np.ndarray = costs.copy() allocation: np.ndarray = self.minimum_cost_method(supplies, demands, costs) total_cost, abs_errors = self.calculate_results(allocation, original_costs) self.show_results(allocation, total_cost, abs_errors) except ValueError: messagebox.showerror("Ошибка", "Все значения должны быть целыми числами.") def minimum_cost_method(self, supplies: np.ndarray, demands: np.ndarray, costs: np.ndarray) -> np.ndarray: """ Метод минимальных элементов для решения транспортной задачи. :param supplies: Запасы для поставщиков. :param demands: Потребности для потребителей. :param costs: Стоимость перевозки между поставщиками и потребителями. :return: Распределение грузов между поставщиками и потребителями. """ allocation: np.ndarray = np.zeros_like(costs) while supplies.sum() > 0 and demands.sum() > 0: min_index: Tuple[int, int] = np.unravel_index(np.argmin(costs, axis=None), costs.shape) # type: ignore i, j = min_index qty: int = min(supplies[i], demands[j]) allocation[i, j] = qty supplies[i] -= qty demands[j] -= qty costs[i, j] = np.inf # Исключить обработанную клетку return allocation def calculate_results(self, allocation: np.ndarray, costs: np.ndarray) -> Tuple[float, np.ndarray]: """ Подсчет общей стоимости перевозок и абсолютных погрешностей для решения задачи. :param allocation: Распределение грузов между поставщиками и потребителями. :param costs: Стоимость перевозки между поставщиками и потребителями. :return: Общая стоимость перевозок и массив абсолютных погрешностей. """ # Замена np.inf на 0 для расчётов costs_no_inf: np.ndarray = np.where(costs == np.inf, 0, costs) total_cost: float = np.sum(allocation * costs_no_inf) abs_errors: np.ndarray = allocation * 0.05 # 5% допустимая погрешность return total_cost, abs_errors def show_results(self, allocation: np.ndarray, total_cost: float, abs_errors: np.ndarray) -> None: """ Отображение результатов решения задачи. :param allocation: Распределение грузов между поставщиками и потребителями. :param total_cost: Общая стоимость перевозок. :param abs_errors: Абсолютные погрешности для каждого элемента распределения. """ results_window: tk.Toplevel = tk.Toplevel(self.root) results_window.title("Результаты") tk.Label(results_window, text="Распределение грузов:").pack(pady=5) allocation_text: tk.Text = tk.Text(results_window, height=10, width=50) allocation_text.insert(tk.END, str(allocation)) allocation_text.config(state=tk.DISABLED) allocation_text.pack() tk.Label(results_window, text=f"Общая стоимость перевозок: {total_cost}").pack(pady=5) tk.Label(results_window, text="Абсолютные погрешности:").pack(pady=5) errors_text: tk.Text = tk.Text(results_window, height=10, width=50) errors_text.insert(tk.END, str(abs_errors)) errors_text.config(state=tk.DISABLED) errors_text.pack() if __name__ == "__main__": root: tk.Tk = tk.Tk() app: TransportProblemApp = TransportProblemApp(root) root.mainloop()