Kodduu Python
1.08K subscribers
311 photos
28 videos
187 links
Научись программировать на Python на интересных примерах

Самый быстрый курс https://stepik.org/a/187914
Самый нескучный курс https://stepik.org/a/185238

Во вопросам сотрудничества: @AlexErf
Download Telegram
This media is not supported in your browser
VIEW IN TELEGRAM
С наступающим 🎄❄️☃️ Сбычи мечт и много хорошего кода в новом 2025 году 🎁👩‍💻🧑‍💻

Подпишись 👉🏻 @KodduuPython 🤖
👍82🔥2
Не успели купить 🎁, подарите знания (любой курс можно подарить):

1️⃣ Python: самый быстрый курс

2️⃣ Python Data Science: самый быстрый курс

👉 Junior Python Data Scientist (программа из курсов 1️⃣ и 2️⃣)

3️⃣ Python в нескучных примерах (50)

👉 Junior Python Developer and Data Scientist (программа из курсов 1️⃣, 2️⃣ и 3️⃣)

4️⃣ Топ 100 вопросов с реальных собеседований по Python (шпаргалка) 👉 бесплатный курс

5️⃣ Язык программирования BrainFuck или ВыносМозга! 👉 бесплатный курс

Подпишись 👉🏻 @KodduuPython 🤖
👍41
Ниже пример простого скрипта на Python, который собирает новогоднее поздравление из случайно выбранных слов и фраз. Его можно расширять, добавлять дополнительные списки или логику по своему вкусу.


import random

def generate_new_year_greeting():
"""
Генерирует новогоднее поздравление, выбирая слова из списков случайным образом.
"""

# Приветствия/начальные фразы
starts = [
"Поздравляю",
"Сердечно поздравляю",
"От всей души приветствую",
"С огромной радостью поздравляю"
]

# Прилагательные/эпитеты
adjectives = [
"счастливого",
"волшебного",
"радостного",
"прекрасного",
"блестящего"
]

# Основные пожелания
wishes = [
"здоровья",
"удачи",
"радости",
"любви",
"тепла",
"творческих успехов",
"исполнения всех желаний"
]

# Дополнительные фразы
extras = [
"чтобы каждый день был наполнен чудесами",
"пусть все мечты сбываются",
"желаю верить в себя и покорять любые вершины",
"пусть в сердце живёт только добро",
"и пусть этот год принесёт много ярких событий"
]

# Заключительные фразы/пожелания
endings = [
"С Новым годом!",
"Пусть в этом году будет всё на высоте!",
"Пусть в новом году будет только лучше!",
"С праздником!",
"Свершений и новых побед!"
]

# Собираем предложение
greeting = (
f"{random.choice(starts)} с наступившим {random.choice(adjectives)} Новым годом!\n\n"
f"Желаю {random.choice(wishes)}, {random.choice(wishes)}, а также {random.choice(wishes)}.\n"
f"И, конечно, {random.choice(extras)}.\n\n"
f"{random.choice(endings)}"
)

return greeting

def main():
# Генерируем и выводим поздравление
print(generate_new_year_greeting())

if __name__ == "__main__":
main()


### Как это работает:
1. Списки со словами и фразами: Для разных частей поздравления (`starts`, adjectives, wishes, extras, `endings`) заведены отдельные списки.
2. Модуль `random`: При помощи random.choice выбирается по одной фразе/слову из каждого списка.
3. Сборка текста: Формируем итоговую строку (`greeting`), используя f-строки с подстановками.
4. Вывод результата: Вызов print(generate_new_year_greeting()) выдаёт нам случайное поздравление на каждом запуске.

При желании можно:
- Добавить больше слов в списки.
- Формировать более сложные конструкции предложений.
- Сохранять поздравление в файл или отправлять его по электронной почте.

Подпишись 👉🏻 @KodduuPython 🤖
👍84
Ниже приведён шуточный пример кода на Python, который «оценивает», сколько салата «Оливье» было съедено во всём мире на Новый год. Все расчёты, конечно, условны и сделаны для иллюстрации, а не на основе реальной статистики.


import random

def estimate_olivier_eaten():
"""
Возвращает приблизительное (и шуточное) количество килограммов Оливье,
которые были съедены на планете в новогоднюю ночь.
"""

# (1) Численность населения (приблизительно, в миллиардах)
world_population = 8.05 # млрд (примерно к 2024 году)

# (2) Процент людей, отмечающих Новый год
# Условно предположим, что его празднуют 80% населения
celebrating_people_percent = 0.8

# (3) Процент любителей Оливье среди тех, кто празднует
# Пусть из празднующих минимум 50% едят Оливье
olivier_lovers_percent = 0.5

# (4) Средняя порция Оливье на человека (в граммах)
# Предположим 300 г на душу – кто-то съест больше, кто-то меньше
avg_portion_per_person_grams = 300

# (5) Считаем
# Сколько людей ест Оливье
number_of_olivier_eaters = world_population * 1_000_000_000 \
* celebrating_people_percent \
* olivier_lovers_percent

# Сколько всего граммов Оливье пришлось на этих людей
total_grams_olivier = number_of_olivier_eaters * avg_portion_per_person_grams

# Переводим в килограммы
total_kilos_olivier = total_grams_olivier / 1000

return total_kilos_olivier

def main():
# Получим оценку
kilos_olivier = estimate_olivier_eaten()

# Для «дополнительной реалистичности» внесём случайный разброс ±10%
# Ведь точное число никто не знает 🙂
fluctuation_percent = random.uniform(-0.1, 0.1)
kilos_olivier *= (1 + fluctuation_percent)

# Красиво форматируем число (например, с разделением разрядов)
result_str = f"{kilos_olivier:,.0f}" # округлим до целых
print(f"По приблизительным (шуточным) оценкам, в новогоднюю ночь "
f"на планете было съедено около {result_str} кг Оливье!")

if __name__ == "__main__":
main()


### Как работает код

1. Параметры «мировой» статистики
- world_population — приблизительная численность населения Земли в миллиардах.
- celebrating_people_percent — доля тех, кто отмечает Новый год.
- olivier_lovers_percent — доля тех, кто в праздничную ночь ест Оливье (из тех, кто вообще празднует).

2. Средняя порция
В примере для простоты взято \(300\) граммов на человека. Кто-то съедает больше, кто-то меньше — но пусть будет так.

3. Вычисление
- Находим общее число людей, которые (гипотетически) ели Оливье.
- Умножаем на 300 г.
- Переводим всё это в килограммы.

4. Случайный разброс
В коде мы добавляем ±10% (переменная `fluctuation_percent`), чтобы сделать оценку ещё менее «точной» и более шутливой.

5. Вывод
В main() печатаем итоговое «псевдо-число» в красиво отформатированном виде.

---

Это, конечно, не настоящее научное исследование, а лишь пример того, как можно реализовать в Python «виртуальный счётчик» чего угодно — например, салата Оливье в новогоднюю ночь.

Подпишись 👉🏻 @KodduuPython 🤖
51
Ниже приведён упрощённый пример на Python, демонстрирующий базовые идеи, которые могли использоваться для плановых расчётов в экономике (как, например, в СССР). Он не претендует на историческую точность и полноту, но иллюстрирует общий подход к задачам планирования с применением математической оптимизации.

---

Краткое введение в задачу

Предположим, что у нас есть несколько типов ресурсов (например, металл, дерево, электроэнергия и т.д.), и мы хотим произвести несколько видов товаров (станки, мебель, автомобили и т.д.). У каждого товара есть:
1. План по выпуску (то есть минимальное количество, которое нужно произвести по указу «сверху»).
2. Потребление ресурсов на единицу выпуска (например, один автомобиль требует 1 тонну металла, 10 кВт⋅ч электроэнергии и т.п.).
3. Ограниченное количество ресурсов, доступных в нашей «народно-хозяйственной» системе.

Основная задача: найти, сколько каждого вида товара нужно произвести, чтобы:
- Выполнить (или превысить) плановые задания (заказ государства).
- Не превысить доступные объёмы ресурсов.
- Максимизировать (или минимизировать) некую целевую функцию — например, суммарную “пользу” (удовлетворение потребностей народа / вклад в экономику).

В реальном СССР и других плановых экономиках задач было в разы больше и сложнее: расчёты производились по десяткам тысяч наименований продукции, учитывалась логистика, взаимозаменяемость ресурсов, отраслевые приоритеты и т.д. В 70–80-х годах это было крайне затруднительно из-за недостатка вычислительной техники и несовершенства методов планирования, что приводило к неточностям, дефицитам и дисбалансам.

Сегодня же, используя современные вычислительные мощности и продвинутые алгоритмы (линейное и нелинейное программирование, машинное обучение, системы принятия решений в реальном времени и т.п.), можно в теории гораздо эффективнее решать плановые задачи. Хотя, конечно, сама концепция плановой экономики поднимает множество вопросов и проблем, выходящих за рамки чисто вычислительной стороны дела.

Сложность плановых расчётов в 70–80-х

Недостаток вычислительной техники. ЭВМ в СССР (например, «Минск», «Урал», ЕС ЭВМ) имели на порядки меньшую производительность по сравнению с современными ПК. В 70–80-е годы такие машины могли обрабатывать относительно простые и не слишком большие задачи. Полноценный учёт сотен тысяч наименований товаров и ресурсов представлял колоссальную computational-проблему.
Ручной труд экономистов и плановиков. Многие расчёты производились вручную, с помощью арифмометров, перфокарт. Часть плановых заданий корректировалась “на местах”, что приводило к искажению общей картины.
Ограничения математических моделей. Методологии линейного программирования, многокритериальной оптимизации и т. п. тогда не были развиты так широко, как сейчас. Вдобавок многие экономические и социальные факторы трудно формализовать линейной моделью.
В результате получался грубый (и часто запаздывающий) план, который вёл к дефициту одних товаров и избытку других, очередям, бартерным схемам и так далее.

Подпишись 👉🏻 @KodduuPython 🤖
## Пример кода на Python

Для решения подобных задач часто применяют библиотеки для линейного программирования (Linear Programming). Одна из популярных библиотек в Python — PuLP. Если её нет, установите командой:

pip install pulp


Ниже приведён пример задачи, где мы хотим произвести три вида продукции: A, B и C.
- Каждый вид продукции требует определённое количество ресурсов (R1 и R2).
- Есть плановый минимум по каждому товару.
- Есть ограничения на объём ресурсов.
- Мы хотим максимизировать так называемую “общественную пользу” (условный показатель важности каждого товара).

### Код


# Пример кода, иллюстрирующего подход к задаче планирования

from pulp import LpProblem, LpMaximize, LpVariable, LpInteger, lpSum, LpStatus, value

# Создаём задачу линейного программирования (ЛП)
problem = LpProblem("SovietPlan", LpMaximize)

# Объявим переменные:
# xA, xB, xC — количество единиц продукции A, B и C, которое мы собираемся произвести.
# для наглядности используем целочисленное программирование (LpInteger),
# хотя в реальности могут быть и вещественные переменные.
xA = LpVariable('xA', lowBound=0, cat=LpInteger)
xB = LpVariable('xB', lowBound=0, cat=LpInteger)
xC = LpVariable('xC', lowBound=0, cat=LpInteger)

# Плановые задания (минимальное количество, которое нужно произвести)
planA = 10
planB = 20
planC = 5

# Коэффициенты потребления ресурсов на единицу каждого товара.
# Пусть ресурс R1 (например, металл) и ресурс R2 (например, электроэнергия).
# Допустим, на производство 1 единицы A нужно 3 ед. R1 и 1 ед. R2,
# на производство 1 единицы B — 2 ед. R1 и 2 ед. R2,
# на производство 1 единицы C — 4 ед. R1 и 3 ед. R2
r1_for_A = 3
r2_for_A = 1

r1_for_B = 2
r2_for_B = 2

r1_for_C = 4
r2_for_C = 3

# Доступное количество ресурсов
R1_available = 100 # например, 100 тонн металла
R2_available = 90 # например, 90 кВт⋅ч условной электроэнергии

# "Польза" (или приоритет) от каждой единицы товара
# В реальном случае это могло бы учитывать потребности населения,
# важность для военной промышленности, экспортный потенциал и т.п.
benefitA = 5
benefitB = 4
benefitC = 6

# Целевая функция: максимизируем суммарную "пользу"
problem += (benefitA * xA + benefitB * xB + benefitC * xC), "Total_Benefit"

# Добавим ограничения

# 1. Выполнение плановых заданий
problem += xA >= planA, "Min_A"
problem += xB >= planB, "Min_B"
problem += xC >= planC, "Min_C"

# 2. Ограничение по ресурсам
problem += (r1_for_A * xA + r1_for_B * xB + r1_for_C * xC) <= R1_available, "Res_R1"
problem += (r2_for_A * xA + r2_for_B * xB + r2_for_C * xC) <= R2_available, "Res_R2"

# Решаем задачу
problem.solve()

# Вывод результатов
print(f"Статус решения: {LpStatus[problem.status]}")
print(f"Оптимальное количество продукции A (xA): {xA.varValue}")
print(f"Оптимальное количество продукции B (xB): {xB.varValue}")
print(f"Оптимальное количество продукции C (xC): {xC.varValue}")
print(f"Максимальная польза: {value(problem.objective)}")


### Интерпретация результатов

1. Статус решения может показать, что задача решена оптимально (`Optimal`) или что оптимального решения нет (если, например, требования слишком высоки и ресурсы не позволяют их удовлетворить).
2. Количество продукции (xA, xB, xC) — сколько штук каждого товара в итоге планируется выпускать.
3. Максимальная польза (value(problem.objective)) показывает значение целевой функции.

Подпишись 👉🏻 @KodduuPython 🤖
Ниже приведу пример задачи из современной практики, которая по своей структуре напоминает упрощённую модель плановой экономики, но уже в контексте цепочек поставок (Supply Chain). Это одна из наиболее распространённых и сложных задач в современной логистике и экономике. В реальных условиях такие задачи включают сотни (а то и тысячи) складов, фабрик, пунктов потребления, видов транспорта и видов продукции.

Пример:
- Есть два завода (Factory1, Factory2), на которых производятся два вида товаров (Product A и Product B).
- Есть два распределительных центра (склада) (DC1, DC2).
- Есть два региона с конечным спросом (Market1, Market2).
- Мы знаем спрос в каждом регионе по каждому товару, ограничения по мощности заводов (сколько каждого товара они могут произвести) и ёмкость складов (сколько там можно держать товаров).
- Мы хотим минимизировать совокупные затраты (произвести товар, перевезти с завода на склад, затем со склада — к конечному потребителю).

Подобная постановка задачи — задача оптимизации в цепочке поставок (supply chain optimization), которая, как и плановая задача, может вырасти до огромных масштабов и требовать значительных вычислительных ресурсов.

---

## Иллюстративный пример на Python (используем библиотеку PuLP)

> Для решения потребуется библиотека PuLP. Установить её можно командой:
>

> pip install pulp
>



from pulp import (
LpProblem, LpMinimize, LpVariable, LpStatus, lpSum, LpInteger, value
)

# ---------------------------
# 1. ДАННЫЕ ЗАДАЧИ
# ---------------------------

# Заводы (factories), Склады (distribution centers), Рынки/регионы (markets)
factories = ["Factory1", "Factory2"]
distribution_centers = ["DC1", "DC2"]
markets = ["Market1", "Market2"]
products = ["ProductA", "ProductB"]

# Производственные мощности (максимальное кол-во единиц товара,
# которое может быть выпущено на каждом заводе)
# form: capacity[завод][продукт]
capacity = {
"Factory1": {"ProductA": 100, "ProductB": 80},
"Factory2": {"ProductA": 120, "ProductB": 100}
}

# Ёмкость складов (сколько всего единиц любых товаров может храниться на складе)
# form: dc_capacity[склад]
dc_capacity = {
"DC1": 150,
"DC2": 150
}

# Спрос в регионах (сколько единиц каждого товара нужно в каждом рынке)
# form: demand[рынок][продукт]
demand = {
"Market1": {"ProductA": 60, "ProductB": 40},
"Market2": {"ProductA": 80, "ProductB": 70}
}

# Себестоимость производства (cost of production) на каждом заводе
# form: production_cost[завод][продукт]
production_cost = {
"Factory1": {"ProductA": 2.0, "ProductB": 3.0},
"Factory2": {"ProductA": 2.5, "ProductB": 2.8}
}

# Стоимость транспортировки с завода до склада (за 1 единицу товара)
# form: transport_cost_factory_dc[(завод, склад)]
transport_cost_factory_dc = {
("Factory1", "DC1"): 0.5,
("Factory1", "DC2"): 0.6,
("Factory2", "DC1"): 0.7,
("Factory2", "DC2"): 0.4
}

# Стоимость транспортировки со склада к рынку (за 1 единицу товара)
# form: transport_cost_dc_market[(склад, рынок)]
transport_cost_dc_market = {
("DC1", "Market1"): 0.3,
("DC1", "Market2"): 0.8,
("DC2", "Market1"): 0.6,
("DC2", "Market2"): 0.5
}

# ---------------------------
# 2. ПОСТАНОВКА ЗАДАЧИ
# ---------------------------
# Создадим задачу линейного программирования: минимизация общих затрат
problem = LpProblem("SupplyChainOptimization", LpMinimize)

# ---------------------------
# 3. ПЕРЕМЕННЫЕ
# ---------------------------
# Пусть:
# x_fdc[p, f, dc] = количество товара p, производимого на заводе f,
# и отправляемого на склад dc
#
# y_dcm[p, dc, m] = количество товара p, отгружаемого со склада dc на рынок m

# Объявим переменные как неотрицательные целые (или неотрицательные непрерывные — зависит от контекста)
x_fdc = {}
for p in products:
for f in factories:
for dc in distribution_centers:
x_fdc[(p, f, dc)] = LpVariable(
f"x_{p}_{f}_{dc}",
lowBound=0,
cat='Continuous'
)
y_dcm = {}
for p in products:
for dc in distribution_centers:
for m in markets:
y_dcm[(p, dc, m)] = LpVariable(
f"y_{p}_{dc}_{m}",
lowBound=0,
cat='Continuous'
)

# ---------------------------
# 4. ЦЕЛЕВАЯ ФУНКЦИЯ
# ---------------------------
# Общие затраты = затраты на производство + затраты на перевозку от завода к складу + от склада к рынку
problem += lpSum(
production_cost[f][p] * x_fdc[(p, f, dc)]
+ transport_cost_factory_dc[(f, dc)] * x_fdc[(p, f, dc)]
for p in products
for f in factories
for dc in distribution_centers
) + lpSum(
transport_cost_dc_market[(dc, m)] * y_dcm[(p, dc, m)]
for p in products
for dc in distribution_centers
for m in markets
), "Total_Cost"

# ---------------------------
# 5. ОГРАНИЧЕНИЯ
# ---------------------------

# (A) Ограничения по производственным мощностям заводов:
# сумма отправленного товара p с завода f на все склады dc <= capacity[f][p]
for f in factories:
for p in products:
problem += lpSum(x_fdc[(p, f, dc)] for dc in distribution_centers) <= capacity[f][p], \
f"ProdCapacity_{f}_{p}"

# (B) Ограничения по ёмкости складов:
# на складе dc общее кол-во хранимых товаров (прибывших от всех заводов)
# не должно превышать dc_capacity[dc],
# но! нужно учесть, что то, что пришло на склад, может сразу уехать на рынок.
# Если мы считаем, что склад одновременно может хранить всё, что приходит,
# и лимит — это некая "пропускная способность", то упростим до:
# Σ(продуктов, заводов) x_fdc <= capacity_dc
# В реальности часто вводят дополнительные переменные для учёта запасов.
# Сделаем упрощённо.
for dc in distribution_centers:
problem += lpSum(x_fdc[(p, f, dc)] for p in products for f in factories) <= dc_capacity[dc], \
f"StorageCapacity_{dc}"

# (C) Баланс на складе (поток товаров через склад):
# кол-во товара p, пришедшее на склад dc, должно быть равно
# кол-ву, которое отгружается дальше в рынки (если мы предполагаем 0 складских запасов в конце).
# Σ(factories) x_fdc = Σ(markets) y_dcm
for dc in distribution_centers:
for p in products:
problem += lpSum(x_fdc[(p, f, dc)] for f in factories) == lpSum(y_dcm[(p, dc, m)] for m in markets), \
f"FlowBalance_{dc}_{p}"

# (D) Удовлетворение спроса в каждом рынке:
# Σ(dc) y_dcm >= demand[m][p]
for m in markets:
for p in products:
problem += lpSum(y_dcm[(p, dc, m)] for dc in distribution_centers) >= demand[m][p], \
f"Demand_{m}_{p}"

# ---------------------------
# 6. РЕШЕНИЕ ЗАДАЧИ
# ---------------------------
problem.solve()

# ---------------------------
# 7. ВЫВОД РЕЗУЛЬТАТОВ
# ---------------------------
print(f"Статус решения: {LpStatus[problem.status]}")
print(f"Минимальные совокупные затраты: {value(problem.objective):.2f}\n")

for (p, f, dc) in x_fdc:
qty = x_fdc[(p, f, dc)].varValue
if qty > 0:
print(f"Производство {p} на {f}, отправка на {dc}: {qty}")

for (p, dc, m) in y_dcm:
qty = y_dcm[(p, dc, m)].varValue
if qty > 0:
print(f"Отгрузка {p} со склада {dc} в {m}: {qty}")


В реальной задаче, особенно если нужно учитывать наличие запасов на складах и временные интервалы, логистические (транспортные) ограничения (наличие вагонов, машин, графики перевозок), затраты на хранение, несколько периодов планирования и прочее, модель становится значительно более сложной и крупной.

Подпишись 👉🏻 @KodduuPython 🤖
6
Ниже приведён пример кода на Python, иллюстрирующего «задачу о маршрутах Деда Мороза» (упрощённая версия задачи коммивояжёра). В ней мы хотим найти оптимальный маршрут Деда Мороза, чтобы он мог доставить подарки в несколько домов (точек на карте), начиная и заканчивая в условном «Лапландском логистическом центре» (или просто в «домике Деда Мороза»).

Здесь мы используем библиотеку OR-Tools от Google (а не `pulp`). Если библиотеки нет, установите её:

pip install ortools


## Пример кода


from ortools.constraint_solver import routing_enums
from ortools.constraint_solver import pywrapcp

def create_data_model():
"""
Создаём структуру с входными данными.
distance_matrix: матрица расстояний между всеми точками (0-я точка — «Лапландия»).
num_vehicles: количество "транспортных средств" (один Дед Мороз).
depot: индекс начальной/конечной точки (тоже «Лапландия»).
"""
data = {}

# Пример: у нас есть 6 домов + 1 "домик Деда Мороза" (всего 7 точек).
# Матрицу расстояний можно задать произвольно или сгенерировать.
# Ниже — условный пример (симметричная матрица).
data['distance_matrix'] = [
# От каждой точки до каждой (0-я строка — расстояния из «Лапландии»).
[0, 10, 15, 20, 25, 30, 12], # Lapland (0) -> ...
[10, 0, 18, 13, 28, 15, 22], # House1 (1) -> ...
[15, 18, 0, 17, 16, 22, 15], # House2 (2)
[20, 13, 17, 0, 14, 19, 23], # House3 (3)
[25, 28, 16, 14, 0, 25, 20], # House4 (4)
[30, 15, 22, 19, 25, 0, 18], # House5 (5)
[12, 22, 15, 23, 20, 18, 0 ], # House6 (6)
]
data['num_vehicles'] = 1 # Дед Мороз «один»
data['depot'] = 0 # Начальная (и конечная) точка — 0, то есть «Лапландия»
return data

def main():
# Создаём данные
data = create_data_model()
distance_matrix = data['distance_matrix']
num_locations = len(distance_matrix) # Всего точек (включая «Лапландию»)
num_vehicles = data['num_vehicles']
depot = data['depot']

# Создаём менеджер маршрутов и модель
manager = pywrapcp.RoutingIndexManager(
num_locations, # кол-во локаций (вершин)
num_vehicles, # кол-во «трансп. средств»
depot # индекс депо (старт/финиш)
)

routing = pywrapcp.RoutingModel(manager)

# Функция-«коллбек», возвращающая расстояние между двумя точками
def distance_callback(from_index, to_index):
# Преобразуем внутренние индексы маршрутизатора в индексы из матрицы
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return distance_matrix[from_node][to_node]

# Регистрируем функцию коллбека и присваиваем ей ID
transit_callback_index = routing.RegisterTransitCallback(distance_callback)
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)

# Зададим параметры поиска (например, стратегию поиска маршрута)
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums.FirstSolutionStrategy.PATH_CHEAPEST_ARC
)

# По желанию — включим какую-нибудь эвристику локального поиска
# search_parameters.local_search_metaheuristic = (
# routing_enums.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH
# )
# search_parameters.time_limit.seconds = 5 # ограничение по времени

# Запускаем решение
solution = routing.SolveWithParameters(search_parameters)
if solution:
# Выводим итоговый маршрут
print("Оптимальный маршрут Деда Мороза (минимальное суммарное расстояние):")
index = routing.Start(0) # начинаем с депо (Лапландия)
plan_output = "Лапландия -> "
route_distance = 0
while not routing.IsEnd(index):
next_index = solution.Value(routing.NextVar(index))
route_distance += routing.GetArcCostForVehicle(index, next_index, 0)
plan_output += f"House{manager.IndexToNode(next_index)} -> "
index = next_index
plan_output += "Лапландия (конец)"
print(plan_output)
print(f"Общее расстояние: {route_distance}")
else:
print("Решение не найдено!")

if __name__ == '__main__':
main()


### Пояснения

1. OR-Tools — это мощная библиотека от Google для решения задач оптимизации (в том числе маршрутизации, линейного и целочисленного программирования, расписаний и т. д.).
2. Ключевые моменты:
- distance_matrix: матрица расстояний между всеми точками (включая точку «Лапландии», где начинается и заканчивается маршрут).
- RoutingIndexManager и RoutingModel: объекты, которые отвечают за «оптимизационную модель».
- distance_callback: функция, которая для каждой пары «откуда–куда» возвращает расстояние.
- В конце мы получаем итоговый маршрут (последовательность посещения домов), чтобы суммарное расстояние было минимальным.

3. Мы предположили, что Дед Мороз должен объехать все дома (узлы) один раз и вернуться в исходную точку (в классической постановке — задача коммивояжёра). В результате мы ищем маршрут, минимизирующий общее расстояние путешествия.

4. В реальном мире можно добавлять множество дополнительных условий:
- Временные окна (должен доставить подарок до определённого времени).
- Ограничения по весу и объёму подарков (если у Деда Мороза несколько волшебных саней).
- Разные скорости движения или разные стоимости поездки (например, снежные заносы).

Но даже в таком упрощённом виде пример показывает, как другая библиотека (OR-Tools), а не PuLP, применяется для решения оптимизационной задачи на тему «доставки подарков Дедом Морозом».

Подпишись 👉🏻 @KodduuPython 🤖
🔥5
NetworkX — это удобная и мощная библиотека для работы с графами на Python. С её помощью можно:

- Создавать графы (ориентированные и неориентированные)
- Добавлять вершины и рёбра
- Находить кратчайшие пути (алгоритмы Дейкстры, Беллмана — Форда и др.)
- Искать связные компоненты, вычислять центральности, кластеризации и многое другое

Ниже — короткий пример, где мы создаём простой граф, добавляем рёбра и ищем кратчайший путь между двумя узлами:


import networkx as nx

# Создадим неориентированный граф
G = nx.Graph()

# Добавим вершины (можно неявно при добавлении рёбер)
G.add_nodes_from(["A", "B", "C", "D", "E"])

# Добавим рёбра с весами
G.add_edge("A", "B", weight=2)
G.add_edge("A", "C", weight=5)
G.add_edge("B", "D", weight=3)
G.add_edge("C", "D", weight=1)
G.add_edge("D", "E", weight=4)

# Ищем кратчайший путь (по весам) из A в E
path = nx.dijkstra_path(G, source="A", target="E", weight="weight")
distance = nx.dijkstra_path_length(G, source="A", target="E", weight="weight")

print("Кратчайший путь A -> E:", path)
print(f"Общая длина пути: {distance}")


NetworkX хорошо подходит для исследований в области сетевых структур, социальных графов, логистики, оптимизации и просто для обучения графовым алгоритмам.

Подпишись 👉🏻 @KodduuPython 🤖
🔥2👍1
Вышла новая статья на pikabu "Как стать АйТишником в 2025 году (пошаговый план)". Суммировал опыт многих, кто пришел в ИТ из других сфер.

Подпишись 👉🏻 @KodduuPython 🤖
🔥5👍21
Ниже приведён прикладной пример использования библиотеки NetworkX для решения простой задачи на графах: представим, что у нас есть небольшая сеть дорог в городе, и мы хотим найти самый быстрый маршрут от склада до магазина с учётом скоростей на участках дорог.

- Узлы графа (nodes) — это перекрёстки.
- Рёбра графа (edges) — это дороги между перекрёстками.
- У каждого ребра есть:
- длина дороги (в километрах),
- скорость (км/ч), с которой можно проехать этот участок.

Целевая метрика: время в пути (в часах). Мы хотим найти кратчайший (по времени) путь, а не по географическому расстоянию.

## Пример кода


import networkx as nx

def build_city_graph():
"""
Создаёт и возвращает ориентированный граф (DiGraph) с атрибутами:
- distance (км)
- speed (км/ч)
"""
G = nx.DiGraph()

# Добавим несколько перекрёстков (можно просто добавлять рёбра,
# тогда вершины создадутся автоматически)
intersections = ["Warehouse", "A", "B", "C", "Store"]
G.add_nodes_from(intersections)

# Добавим дороги (рёбра) с атрибутами:
# G.add_edge(откуда, куда, distance=..., speed=...)
G.add_edge("Warehouse", "A", distance=3.0, speed=30.0)
G.add_edge("Warehouse", "B", distance=5.0, speed=40.0)
G.add_edge("A", "C", distance=2.0, speed=20.0)
G.add_edge("B", "C", distance=2.5, speed=35.0)
G.add_edge("C", "Store", distance=4.0, speed=40.0)
G.add_edge("A", "Store", distance=8.0, speed=60.0)

# Можно добавить и обратные направления, если дороги двусторонние
G.add_edge("A", "Warehouse", distance=3.0, speed=30.0)
G.add_edge("B", "Warehouse", distance=5.0, speed=40.0)
# И так далее...

return G

def compute_travel_time(u, v, data):
"""
Вычисляем время (часы) проезда по участку (u->v) на основе атрибутов distance и speed.
data — словарь атрибутов ребра.
"""
dist = data.get("distance", 1.0)
spd = data.get("speed", 1.0)
return dist / spd # время = расстояние/скорость

def main():
# 1. Строим граф
G = build_city_graph()

# 2. Считаем «вес» каждого ребра как время
# Для поиска кратчайшего пути по времени используем атрибуты distance и speed.
# NetworkX позволяет указать коллбэк (функцию), которая вычисляет вес «на лету»,
# но здесь, для наглядности, прямо создадим новый атрибут "time".
for u, v, data in G.edges(data=True):
data["time"] = compute_travel_time(u, v, data)

# 3. Ищем кратчайший маршрут по атрибуту "time"
start = "Warehouse"
end = "Store"

# Используем алгоритм Дейкстры (dijkstra_path) или любой другой
path = nx.dijkstra_path(G, source=start, target=end, weight="time")
total_time = nx.dijkstra_path_length(G, source=start, target=end, weight="time")

print("Самый быстрый маршрут:", " -> ".join(path))
print(f"Общее время в пути (часы): {total_time:.2f}")

if __name__ == "__main__":
main()


### Что происходит в коде?

1. build_city_graph() — создаёт ориентированный граф (DiGraph). Каждая дорога (ребро) имеет:
- distance: длина участка (км),
- speed: доступная скорость движения (км/ч).

2. compute_travel_time() — функция для расчёта времени в пути (в часах) = \(\text{distance} / \text{speed}\).

3. Мы в цикле по всем рёбрам графа (G.edges(data=True)) создаём новый атрибут time, который потом используется в алгоритме Дейкстры.

4. nx.dijkstra_path и nx.dijkstra_path_length — стандартные методы NetworkX для нахождения кратчайшего пути и его «стоимости» (суммы весов) в взвешенном графе:
- source=start, target=end, weight="time" указывает, что в качестве веса ребра следует использовать именно атрибут time.

5. На выходе — маршрут (список перекрёстков) и итоговое время.

NetworkX даёт удобный способ моделировать любые сетевые структуры (дорожные сети, социальные графы, электрические сети и т. д.), используя множество готовых алгоритмов (поиск кратчайшего пути, анализ центральности, минимальное остовное дерево, поиск компонент связности и многое другое).

Подпишись 👉🏻 @KodduuPython 🤖
👍71
До 12 января действует скидка на программу Junior Python Developer и Data Scientist +интервью тесты 🔥🔥🔥

Программа включает в себя курс по Python, по Python Data Sceince, CookBook для практики Python и "Топ 100 вопросов с реальных собеседований по Python (+тесты)" 🔥🔥🔥

Подпишись 👉🏻 @KodduuPython 🤖