Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

5 курс / lab3

.py
Скачиваний:
0
Добавлен:
26.01.2026
Размер:
14.54 Кб
Скачать
import time
from typing import List, Tuple, Dict


class Item:
    def __init__(self, name: str, weight: float, value: float):
        self.name = name
        self.weight = weight
        self.value = value

    def __str__(self):
        return f"{self.name} (вес: {self.weight}, ценность: {self.value})"

    def __repr__(self):
        return self.__str__()

    @property
    def value_per_weight(self):
        return self.value / self.weight if self.weight > 0 else 0


class Knapsack:
    def __init__(self, max_weight: float = 10.0):
        self.max_weight = max_weight
        self.current_weight = 0.0
        self.items = []
        self.total_value = 0.0

    def add_item(self, item: Item):
        if self.current_weight + item.weight <= self.max_weight:
            self.items.append(item)
            self.current_weight += item.weight
            self.total_value += item.value
            return True
        return False

    def clear(self):
        self.items = []
        self.current_weight = 0.0
        self.total_value = 0.0

    def __str__(self):
        return (f"Рюкзак (макс. вес: {self.max_weight}, текущий вес: {self.current_weight:.2f}, "
                f"стоимость: {self.total_value:.2f})\nПредметы: {self.items}")


class KnapsackSolver:
    def __init__(self, items: List[Item]):
        self.items = items
        self.n = len(items)

    def recursive_solve(self, capacity: float) -> Tuple[List[Item], float]:
        def rec(i: int, w: float):
            if i == 0 or w == 0:
                return 0, []

            if self.items[i - 1].weight > w:
                return rec(i - 1, w)


            value_with, items_with = rec(i - 1, w - self.items[i - 1].weight)
            value_with += self.items[i - 1].value


            value_without, items_without = rec(i - 1, w)

            if value_with > value_without:
                return value_with, items_with + [self.items[i - 1]]
            else:
                return value_without, items_without

        max_value, selected_items = rec(self.n, capacity)
        return selected_items, max_value

    def dp_solve(self, capacity: float) -> Tuple[List[Item], float]:

        dp = [[0] * (int(capacity) + 1) for _ in range(self.n + 1)]


        for i in range(1, self.n + 1):
            for w in range(1, int(capacity) + 1):
                if self.items[i - 1].weight <= w:
                    dp[i][w] = max(dp[i - 1][w],
                                   dp[i - 1][w - int(self.items[i - 1].weight)] + self.items[i - 1].value)
                else:
                    dp[i][w] = dp[i - 1][w]


        max_value = dp[self.n][int(capacity)]
        selected_items = []
        w = int(capacity)

        for i in range(self.n, 0, -1):
            if dp[i][w] != dp[i - 1][w]:
                selected_items.append(self.items[i - 1])
                w -= int(self.items[i - 1].weight)

        selected_items.reverse()
        return selected_items, max_value

    def greedy_solve_by_weight(self, capacity: float) -> Tuple[List[Item], float]:

        sorted_items = sorted(self.items, key=lambda x: x.weight, reverse=True)

        knapsack = Knapsack(capacity)
        for item in sorted_items:
            knapsack.add_item(item)

        return knapsack.items, knapsack.total_value

    def greedy_solve_by_value_per_weight(self, capacity: float) -> Tuple[List[Item], float]:

        sorted_items = sorted(self.items, key=lambda x: x.value_per_weight, reverse=True)

        knapsack = Knapsack(capacity)
        for item in sorted_items:
            knapsack.add_item(item)

        return knapsack.items, knapsack.total_value


class KnapsackApp:
    def __init__(self):
        self.items = []
        self.knapsack = Knapsack()
        self.solver = None
        self.results = {}

    def load_from_file(self, filename: str):
        try:
            with open(filename, 'r', encoding='utf-8') as f:
                for line in f:
                    if line.strip():
                        parts = line.strip().split(',')
                        if len(parts) >= 3:
                            name = parts[0].strip()
                            weight = float(parts[1].strip())
                            value = float(parts[2].strip())
                            self.items.append(Item(name, weight, value))
            print(f"Загружено {len(self.items)} предметов")
            self.solver = KnapsackSolver(self.items)
        except FileNotFoundError:
            print(f"Файл {filename} не найден")
        except Exception as e:
            print(f"Ошибка при загрузке файла: {e}")

    def add_item(self):
        name = input("Введите название предмета: ")
        try:
            weight = float(input("Введите вес предмета: "))
            value = float(input("Введите ценность предмета: "))
            self.items.append(Item(name, weight, value))
            self.solver = KnapsackSolver(self.items)
            print("Предмет добавлен")
        except ValueError:
            print("Ошибка: введите корректные числа")

    def edit_item(self):
        self.show_items()
        try:
            index = int(input("Введите индекс предмета для редактирования: ")) - 1
            if 0 <= index < len(self.items):
                item = self.items[index]
                print(f"Редактирование: {item}")
                name = input(f"Название [{item.name}]: ") or item.name
                weight = input(f"Вес [{item.weight}]: ")
                weight = float(weight) if weight else item.weight
                value = input(f"Ценность [{item.value}]: ")
                value = float(value) if value else item.value

                self.items[index] = Item(name, weight, value)
                self.solver = KnapsackSolver(self.items)
                print("Предмет изменен")
            else:
                print("Неверный индекс")
        except ValueError:
            print("Ошибка: введите корректный индекс")

    def delete_item(self):
        self.show_items()
        try:
            index = int(input("Введите индекс предмета для удаления: ")) - 1
            if 0 <= index < len(self.items):
                removed = self.items.pop(index)
                self.solver = KnapsackSolver(self.items)
                print(f"Удален предмет: {removed}")
            else:
                print("Неверный индекс")
        except ValueError:
            print("Ошибка: введите корректный индекс")

    def set_max_weight(self):
        try:
            weight = float(input("Введите максимальный вес рюкзака: "))
            if weight > 0:
                self.knapsack.max_weight = weight
                print(f"Максимальный вес установлен: {weight}")
            else:
                print("Вес должен быть положительным")
        except ValueError:
            print("Ошибка: введите корректное число")

    def show_knapsack(self):
        print("\n" + "=" * 50)
        print("СОДЕРЖИМОЕ РЮКЗАКА")
        print("=" * 50)
        print(self.knapsack)
        print("=" * 50)

    def show_items(self):
        print("\n" + "=" * 50)
        print("СПИСОК ПРЕДМЕТОВ")
        print("=" * 50)
        for i, item in enumerate(self.items, 1):
            print(f"{i}. {item}")
        print("=" * 50)

    def solve_problem(self):
        if not self.items:
            print("Сначала добавьте предметы")
            return

        print("\nВыберите метод решения:")
        print("1. Рекурсивный метод")
        print("2. Метод динамического программирования")
        print("3. Жадный алгоритм (по максимальному весу)")
        print("4. Жадный алгоритм (по максимальному соотношению цена/вес)")

        try:
            choice = int(input("Ваш выбор: "))


            self.knapsack.clear()

            start_time = time.time()

            if choice == 1:
                items, value = self.solver.recursive_solve(self.knapsack.max_weight)
                method_name = "Рекурсивный метод"
            elif choice == 2:
                items, value = self.solver.dp_solve(self.knapsack.max_weight)
                method_name = "ДП метод"
            elif choice == 3:
                items, value = self.solver.greedy_solve_by_weight(self.knapsack.max_weight)
                method_name = "Жадный (по весу)"
            elif choice == 4:
                items, value = self.solver.greedy_solve_by_value_per_weight(self.knapsack.max_weight)
                method_name = "Жадный (цена/вес)"
            else:
                print("Неверный выбор")
                return

            end_time = time.time()
            execution_time = end_time - start_time


            for item in items:
                self.knapsack.add_item(item)

            self.results[method_name] = {
                'value': value,
                'time': execution_time,
                'items': len(items),
                'weight': sum(item.weight for item in items)
            }

            print(f"\nРезультат ({method_name}):")
            print(f"Стоимость: {value:.2f}")
            print(f"Время выполнения: {execution_time:.6f} сек")
            print(f"Количество предметов: {len(items)}")
            self.show_knapsack()

        except ValueError:
            print("Ошибка: введите число от 1 до 4")

    def compare_methods(self):
        if not self.items:
            print("Сначала добавьте предметы")
            return

        print("\n" + "=" * 80)
        print("СРАВНЕНИЕ МЕТОДОВ")
        print("=" * 80)

        methods = [
            ("Рекурсивный", self.solver.recursive_solve),
            ("ДП", self.solver.dp_solve),
            ("Жадный (вес)", self.solver.greedy_solve_by_weight),
            ("Жадный (цена/вес)", self.solver.greedy_solve_by_value_per_weight)
        ]

        results = {}

        for name, method in methods:
            start_time = time.time()
            items, value = method(self.knapsack.max_weight)
            end_time = time.time()

            results[name] = {
                'value': value,
                'time': end_time - start_time,
                'items': len(items),
                'weight': sum(item.weight for item in items)
            }


        print(f"{'Метод':<20} {'Стоимость':<12} {'Время (сек)':<15} {'Предметы':<10} {'Вес':<10}")
        print("-" * 80)

        for name, data in results.items():
            print(f"{name:<20} {data['value']:<12.2f} {data['time']:<15.6f} "
                  f"{data['items']:<10} {data['weight']:<10.2f}")


        best_by_value = max(results.items(), key=lambda x: x[1]['value'])
        print(f"\nЛучший метод по стоимости: {best_by_value[0]} ({best_by_value[1]['value']:.2f})")


        fastest = min(results.items(), key=lambda x: x[1]['time'])
        print(f"Самый быстрый метод: {fastest[0]} ({fastest[1]['time']:.6f} сек)")

        print("=" * 80)

    def run(self):
        while True:
            print("\n" + "=" * 50)
            print("МЕНЮ")
            print("=" * 50)
            print("1. Загрузить предметы из файла")
            print("2. Добавить предмет")
            print("3. Изменить предмет")
            print("4. Удалить предмет")
            print("5. Задать максимальный вес рюкзака")
            print("6. Просмотреть содержимое рюкзака")
            print("7. Выбрать способ решения")
            print("8. Сравнить способы решения")
            print("9. Показать все предметы")
            print("0. Выход")
            print("=" * 50)

            choice = input("Ваш выбор: ")

            if choice == '1':
                filename = input("Введите имя файла: ")
                self.load_from_file(filename)
            elif choice == '2':
                self.add_item()
            elif choice == '3':
                self.edit_item()
            elif choice == '4':
                self.delete_item()
            elif choice == '5':
                self.set_max_weight()
            elif choice == '6':
                self.show_knapsack()
            elif choice == '7':
                self.solve_problem()
            elif choice == '8':
                self.compare_methods()
            elif choice == '9':
                self.show_items()
            elif choice == '0':
                print("Выход из программы")
                break
            else:
                print("Неверный выбор")


def create_sample_file(filename: str = "items.txt"):
    sample_data = """ноутбук, 2.5, 500
книга, 1.0, 50
кошелек, 0.3, 100
фонарик, 0.5, 30
вода, 1.5, 10
аптечка, 1.2, 80
куртка, 1.8, 150
еда, 1.0, 40
планшет, 1.0, 300
палатка, 3.0, 200"""

    with open(filename, 'w', encoding='utf-8') as f:
        f.write(sample_data)
    print(f"Создан пример файла {filename}")


if __name__ == "__main__":
    create_sample_file("items.txt")

    app = KnapsackApp()
    app.run()
Соседние файлы в папке 5 курс