[{"data":1,"prerenderedAt":2085},["ShallowReactive",2],{"navigation":3,"/blog/python/st32":378,"/blog/python/st32-surround":2080},[4],{"title":5,"path":6,"stem":7,"children":8,"page":114},"Blog","/blog","blog",[9,115,184,321],{"title":10,"path":11,"stem":12,"children":13,"page":114},"Ege","/blog/ege","blog/ege",[14,18,22,26,30,34,38,42,46,50,54,58,62,66,70,74,78,82,86,90,94,98,102,106,110],{"title":15,"path":16,"stem":17},"ЕГЭ Задание 1","/blog/ege/task1","blog/ege/task1",{"title":19,"path":20,"stem":21},"ЕГЭ Задание 10","/blog/ege/task10","blog/ege/task10",{"title":23,"path":24,"stem":25},"ЕГЭ Задание 11","/blog/ege/task11","blog/ege/task11",{"title":27,"path":28,"stem":29},"ЕГЭ Задание 12","/blog/ege/task12","blog/ege/task12",{"title":31,"path":32,"stem":33},"ЕГЭ Задание 13","/blog/ege/task13","blog/ege/task13",{"title":35,"path":36,"stem":37},"ЕГЭ Задание 14","/blog/ege/task14","blog/ege/task14",{"title":39,"path":40,"stem":41},"ЕГЭ Задание 15","/blog/ege/task15","blog/ege/task15",{"title":43,"path":44,"stem":45},"ЕГЭ Задание 16","/blog/ege/task16","blog/ege/task16",{"title":47,"path":48,"stem":49},"ЕГЭ Задание 17","/blog/ege/task17","blog/ege/task17",{"title":51,"path":52,"stem":53},"ЕГЭ Задание 18","/blog/ege/task18","blog/ege/task18",{"title":55,"path":56,"stem":57},"ЕГЭ Задание 19, 20, 21","/blog/ege/task19_20_21","blog/ege/task19_20_21",{"title":59,"path":60,"stem":61},"ЕГЭ Задание 2","/blog/ege/task2","blog/ege/task2",{"title":63,"path":64,"stem":65},"ЕГЭ Задание 22","/blog/ege/task22","blog/ege/task22",{"title":67,"path":68,"stem":69},"ЕГЭ Задание 23","/blog/ege/task23","blog/ege/task23",{"title":71,"path":72,"stem":73},"ЕГЭ Задание 24","/blog/ege/task24","blog/ege/task24",{"title":75,"path":76,"stem":77},"ЕГЭ Задание 25","/blog/ege/task25","blog/ege/task25",{"title":79,"path":80,"stem":81},"ЕГЭ Задание 26","/blog/ege/task26","blog/ege/task26",{"title":83,"path":84,"stem":85},"ЕГЭ Задание 27","/blog/ege/task27","blog/ege/task27",{"title":87,"path":88,"stem":89},"ЕГЭ Задание 3","/blog/ege/task3","blog/ege/task3",{"title":91,"path":92,"stem":93},"ЕГЭ Задание 4","/blog/ege/task4","blog/ege/task4",{"title":95,"path":96,"stem":97},"ЕГЭ Задание 5","/blog/ege/task5","blog/ege/task5",{"title":99,"path":100,"stem":101},"ЕГЭ Задание 6","/blog/ege/task6","blog/ege/task6",{"title":103,"path":104,"stem":105},"ЕГЭ Задание 7","/blog/ege/task7","blog/ege/task7",{"title":107,"path":108,"stem":109},"ЕГЭ Задание 8","/blog/ege/task8","blog/ege/task8",{"title":111,"path":112,"stem":113},"ЕГЭ Задание 9","/blog/ege/task9","blog/ege/task9",false,{"title":116,"path":117,"stem":118,"children":119,"page":114},"Oge","/blog/oge","blog/oge",[120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180],{"title":121,"path":122,"stem":123},"ОГЭ Задание 1","/blog/oge/task1","blog/oge/task1",{"title":125,"path":126,"stem":127},"ОГЭ Задание 10","/blog/oge/task10","blog/oge/task10",{"title":129,"path":130,"stem":131},"ОГЭ Задание 11","/blog/oge/task11","blog/oge/task11",{"title":133,"path":134,"stem":135},"ОГЭ Задание 12","/blog/oge/task12","blog/oge/task12",{"title":137,"path":138,"stem":139},"ОГЭ Задание 13","/blog/oge/task13","blog/oge/task13",{"title":141,"path":142,"stem":143},"ОГЭ Задание 14","/blog/oge/task14","blog/oge/task14",{"title":145,"path":146,"stem":147},"ОГЭ Задание 15","/blog/oge/task15","blog/oge/task15",{"title":149,"path":150,"stem":151},"ОГЭ Задание 16","/blog/oge/task16","blog/oge/task16",{"title":153,"path":154,"stem":155},"ОГЭ Задание 2","/blog/oge/task2","blog/oge/task2",{"title":157,"path":158,"stem":159},"ОГЭ Задание 3","/blog/oge/task3","blog/oge/task3",{"title":161,"path":162,"stem":163},"ОГЭ Задание 4","/blog/oge/task4","blog/oge/task4",{"title":165,"path":166,"stem":167},"ОГЭ Задание 5","/blog/oge/task5","blog/oge/task5",{"title":169,"path":170,"stem":171},"ОГЭ Задание 6","/blog/oge/task6","blog/oge/task6",{"title":173,"path":174,"stem":175},"ОГЭ Задание 7","/blog/oge/task7","blog/oge/task7",{"title":177,"path":178,"stem":179},"ОГЭ Задание 8","/blog/oge/task8","blog/oge/task8",{"title":181,"path":182,"stem":183},"ОГЭ Задание 9","/blog/oge/task9","blog/oge/task9",{"title":185,"path":186,"stem":187,"children":188,"page":114},"Python","/blog/python","blog/python",[189,193,197,201,205,209,213,217,221,225,229,233,237,241,245,249,253,257,261,265,269,273,277,281,285,289,293,297,301,305,309,313,317],{"title":190,"path":191,"stem":192},"Знакомство с синтаксисом","/blog/python/st1","blog/python/st1",{"title":194,"path":195,"stem":196},"Отладка","/blog/python/st10","blog/python/st10",{"title":198,"path":199,"stem":200},"Модули и пакеты","/blog/python/st11","blog/python/st11",{"title":202,"path":203,"stem":204},"Кортежи","/blog/python/st12","blog/python/st12",{"title":206,"path":207,"stem":208},"Знакомство со списками","/blog/python/st13","blog/python/st13",{"title":210,"path":211,"stem":212},"Списки и циклы","/blog/python/st14","blog/python/st14",{"title":214,"path":215,"stem":216},"Использование списков ч.1","/blog/python/st15","blog/python/st15",{"title":218,"path":219,"stem":220},"Использование списков ч.2","/blog/python/st16","blog/python/st16",{"title":222,"path":223,"stem":224},"Использование списков ч.3","/blog/python/st17","blog/python/st17",{"title":226,"path":227,"stem":228},"Словари","/blog/python/st18","blog/python/st18",{"title":230,"path":231,"stem":232},"Множества","/blog/python/st19","blog/python/st19",{"title":234,"path":235,"stem":236},"Переменные","/blog/python/st2","blog/python/st2",{"title":238,"path":239,"stem":240},"Хеш-таблицы","/blog/python/st20","blog/python/st20",{"title":242,"path":243,"stem":244},"Решето Эратосфена","/blog/python/st21","blog/python/st21",{"title":246,"path":247,"stem":248},"Длинная арифметика","/blog/python/st22","blog/python/st22",{"title":250,"path":251,"stem":252},"Декораторы функций","/blog/python/st23","blog/python/st23",{"title":254,"path":255,"stem":256},"Знакомство с алгоритмами","/blog/python/st24","blog/python/st24",{"title":258,"path":259,"stem":260},"Бинарный поиск – примеры задач","/blog/python/st25","blog/python/st25",{"title":262,"path":263,"stem":264},"Сортировка выбором","/blog/python/st26","blog/python/st26",{"title":266,"path":267,"stem":268},"Рекурсия и стек","/blog/python/st27","blog/python/st27",{"title":270,"path":271,"stem":272},"Быстрая сортировка","/blog/python/st28","blog/python/st28",{"title":274,"path":275,"stem":276},"Поиск в ширину","/blog/python/st29","blog/python/st29",{"title":278,"path":279,"stem":280},"Работа со строками","/blog/python/st3","blog/python/st3",{"title":282,"path":283,"stem":284},"Поиск в глубину","/blog/python/st30","blog/python/st30",{"title":286,"path":287,"stem":288},"Сбалансированные деревья","/blog/python/st31","blog/python/st31",{"title":290,"path":291,"stem":292},"Алгоритм Дейкстры","/blog/python/st32","blog/python/st32",{"title":294,"path":295,"stem":296},"Жадные алгоритмы","/blog/python/st33","blog/python/st33",{"title":298,"path":299,"stem":300},"Типы данных","/blog/python/st4","blog/python/st4",{"title":302,"path":303,"stem":304},"О функциях","/blog/python/st5","blog/python/st5",{"title":306,"path":307,"stem":308},"Свойства и методы","/blog/python/st6","blog/python/st6",{"title":310,"path":311,"stem":312},"Определение функций","/blog/python/st7","blog/python/st7",{"title":314,"path":315,"stem":316},"Логика","/blog/python/st8","blog/python/st8",{"title":318,"path":319,"stem":320},"Циклы","/blog/python/st9","blog/python/st9",{"title":322,"path":323,"stem":324,"children":325,"page":114},"Toi","/blog/toi","blog/toi",[326,330,334,338,342,346,350,354,358,362,366,370,374],{"title":327,"path":328,"stem":329},"Информация и информационные процессы","/blog/toi/st1","blog/toi/st1",{"title":331,"path":332,"stem":333},"Электронные таблицы","/blog/toi/st10","blog/toi/st10",{"title":335,"path":336,"stem":337},"Система, её свойства и компоненты. Моделирование","/blog/toi/st11","blog/toi/st11",{"title":339,"path":340,"stem":341},"Представление информации в компьютере","/blog/toi/st12","blog/toi/st12",{"title":343,"path":344,"stem":345},"Средства информационно-коммуникационных технологий. Файловая система","/blog/toi/st13","blog/toi/st13",{"title":347,"path":348,"stem":349},"Комбинаторика","/blog/toi/st2","blog/toi/st2",{"title":351,"path":352,"stem":353},"Адресация в интернете","/blog/toi/st3","blog/toi/st3",{"title":355,"path":356,"stem":357},"Измерение количества информации","/blog/toi/st4","blog/toi/st4",{"title":359,"path":360,"stem":361},"Системы счисления","/blog/toi/st5","blog/toi/st5",{"title":363,"path":364,"stem":365},"Диаграммы Эйлера — Венна","/blog/toi/st6","blog/toi/st6",{"title":367,"path":368,"stem":369},"Условие Фано","/blog/toi/st7","blog/toi/st7",{"title":371,"path":372,"stem":373},"Теория графов","/blog/toi/st8","blog/toi/st8",{"title":375,"path":376,"stem":377},"Алгебра логики","/blog/toi/st9","blog/toi/st9",{"id":379,"title":290,"author":380,"body":385,"date":2073,"description":2074,"extension":2075,"image":2076,"meta":2077,"minRead":1787,"navigation":1510,"num":1835,"path":291,"seo":2078,"stem":292,"__hash__":2079},"python/blog/python/st32.md",{"name":381,"avatar":382},"Штана Альберт Игоревич",{"src":383,"alt":384},"me.jpg","@ashtana",{"type":386,"value":387,"toc":2062},"minimark",[388,392,397,408,415,423,428,431,438,441,457,463,466,472,475,484,490,493,496,507,510,516,521,524,528,534,540,551,554,557,560,564,567,573,576,579,585,588,593,598,604,607,613,619,625,635,638,641,651,654,664,667,670,673,679,682,686,689,695,698,704,707,713,716,722,725,731,748,752,755,761,764,790,793,854,861,891,894,934,937,1037,1044,1114,1117,1170,1173,1191,1194,1364,1371,1489,1492,1495,2029,2037,2040,2044,2055,2058],[389,390,290],"h2",{"id":391},"алгоритм-дейкстры",[393,394],"card-collapsible",{":isList":395,"title":396},"[\"Узнаете о взвешенных графах, где рёбрам назначаются большие или меньшие веса.\",\"Изучите алгоритм Дейкстры, который позволяет получить ответ на вопрос: \\\"Как выглядит кратчайший путь к X?\\\" на взвешенных графах.\",\"Узнаете о циклах в графах, для которых алгоритм Дейкстры не работает.\"]","Из этой статьи вы",[398,399,400],"blockquote",{},[401,402,403,404,407],"p",{},"В предыдущей статье были рассмотрены сбалансированные деревья: ",[405,406,286],"a",{"href":287},".\nЗдесь далее текст пойдёт о взвешенных графах и алгоритме Эдсгера Дейкстры.",[401,409,410,411,414],{},"В статье про ",[405,412,413],{"href":275},"поиск в ширину"," можно увидеть, как найти путь из точки А в точку В.\nНайденный путь не обязательно окажется самым быстрым.\nЭтот путь считается кратчайшим только потому что состоит из наименьшего числа сегментов(рёбер).\nНо представим, что с каждым сегментом связывается продолжительность перемещения.\nИ тогда может выясниться, что существует не самый кратчайший, но более быстрый путь.",[401,416,417,418,422],{},"Алгоритм поиска в ширину находит путь с минимальным количеством сегментов(рёбер у графа).\nА если необходимо найти самый быстрый путь? Быстрее всего его найти при помощи ",[419,420,421],"em",{},"алгоритма Дейкстры",".",[424,425,427],"h3",{"id":426},"работа-алгоритма-дейкстры","Работа алгоритма Дейкстры",[401,429,430],{},"Посмотрим на граф и как алгоритм Дейкстры поработает с таким графом.",[401,432,433],{},[434,435],"img",{"alt":436,"src":437},"Пример взвешенного графа","/images/blog/python/st32/img_1.png",[401,439,440],{},"Каждому ребру назначается время перемещения, например, в минутах.\nАлгоритм Дейкстры используется для поиска пути от начальной точки к конечной за кратчайшее возможное время.\nПрименив к этому графу поиск в ширину, вы получите следующий кратчайший путь: начало → А → конец.\nЭтот путь занимает 7 минут.\nА может существовать путь, который займёт меньше времени? Алгоритм Дейкстры состоит из четырёх шагов:",[442,443,444,448,451,454],"ol",{},[445,446,447],"li",{},"Найти узел с наименьшей стоимостью (т.е. узел, до которого можно добраться за минимальное время);",[445,449,450],{},"Обновить стоимости соседей этого узла;",[445,452,453],{},"Повторять, пока это не будет сделано для всех узлов графа;",[445,455,456],{},"Вычислить итоговый путь.",[401,458,459,462],{},[419,460,461],{},"Шаг 1:"," найти узел с наименьшей стоимость. В самом начале выбираем, куда направиться: к узлу A или узлу B?\nСколько времени необходимо, чтобы добраться до каждого из этих узлов?",[401,464,465],{},"До узла A – 7 минут, а до узла B – 3 минуты. Что касается остальных узлов, о них алгоритм пока ничего не знает.\nТак как время достижения конечного узла остаётся неизвестным, считается, что оно бесконечно.\nУзел B – ближайший, т.к. до него всего 3 минуты.",[401,467,468,471],{},[419,469,470],{},"Шаг 2:"," вычислить, сколько времени потребуется для того, чтобы добраться до всех внешних соседей B при переходе по ребру из B.\nПри этом обнаруживается более короткий путь к узлу A. Ранее до перехода к нему требовалось 7 минут, теперь же 6.",[401,473,474],{},"Если находится таким способом, более короткий путь для соседа B, то необходимо обновить его стоимость.\nВ данном случае найдено:",[476,477,478,481],"ul",{},[445,479,480],{},"более короткий путь к A (сокращение с 7 до 6 минут);",[445,482,483],{},"первый путь к конечному узлу до 8 минут.",[401,485,486,489],{},[419,487,488],{},"Шаг 3:"," повторение.",[401,491,492],{},"Снова выполняется шаг 1. С узлом B работа закончена, поэтому наименьшая оценка по времени производится по узлу A.",[401,494,495],{},"Снова выполняется шаг 2. Обновляем стоимости внешних соседей для узла A.\nАлгоритм вычисляет, что путь до конечного узла теперь занимает 7 минут! Алгоритм на этом завершается.\nК моменту завершения работы алгоритма становится известно:",[476,497,498,501,504],{},[445,499,500],{},"Чтобы добраться до узла B, нужно 3 минуты;",[445,502,503],{},"Чтобы добрать до узла A, нужно 6 минут;",[445,505,506],{},"Чтобы добраться до конечного узла, нужно 7 минут.",[401,508,509],{},"Последний шаг – вычисление итогового пути(разберёмся с ним ниже). А пока просто посмотрим как выглядит итоговой путь:",[401,511,512],{},[434,513],{"alt":514,"src":515},"Пример взвешенного графа: итоговый путь","/images/blog/python/st32/img_2.png",[398,517,518],{},[401,519,520],{},"Алгоритм поиска в ширину не найдёт этот путь как кратчайший, потому что он состоит из трёх рёбер, а от начального до конечного можно добраться всего по двум рёбрам графа.",[401,522,523],{},"В предыдущей статье было описание использования алгоритма поиска в ширину для нахождения кратчайшего пути на графе между двумя точками.\nВ той статье под \"кратчайшим путём\" понимался путь с минимальным количеством сегментов.\nС другой стороны, в алгоритме Дейкстры каждому сегменту(ребру графа) присваивается число(вес), а алгоритм Дейкстры находит путь с наименьшим суммарным весом.",[424,525,527],{"id":526},"терминология","Терминология",[401,529,530,531,422],{},"Разберёмся с терминологией.\nКогда используется алгоритм Дейкстры, с каждым ребром графа связывается число, называемое ",[419,532,533],{},"весом",[401,535,536],{},[434,537],{"alt":538,"src":539},"Пример взвешенного графа: веса","/images/blog/python/st32/img_3.png",[401,541,542,543,546,547,550],{},"Граф с весами называется ",[419,544,545],{},"взвешенным графом",". Граф без весов называется ",[419,548,549],{},"невзвешенным графом",".\nДля вычисления кратчайшего пути в невзвешенном графе используется алгоритм поиска в ширину.\nКратчайшие пути во взвешенном графе вычисляются по алгоритму Дейкстры.",[401,552,553],{},"В графах также могут присутствовать циклы.\nЭто означает, что можно из некоторого узла, перемещаться по графу, а потом снова оказаться в том же узле.\nЕсть ли смысл перемещаться по циклу для поиска кратчайшего пути? Правильнее будет использовать путь без прохождения цикла.\nЕсли алгоритму обхода графа пройти по циклу и снова оказаться в том же узле, то цикл лишь добавит лишний вес.\nМожно обойти цикл и два и трижды и т.д., но это лишь добавит лишний вес и увеличит суммарный вес для всего пути.\nСледовательно, путь обхода через цикл или используя цикл — никогда не будет кратчайшим.",[401,555,556],{},"Наконец, существует понятие направленных и ненаправленных графов.\nСамо понятие ненаправленного графа означает, что каждый из двух узлов соединённых путём фактически ведёт к другому узлу. Это может быть и цикл.\nВ ненаправленном графе каждое новое ребро добавляет ещё один цикл.\nАлгоритм Дейкстры работает только с графами, в которых нет циклов и где все рёбра неотрицательны.",[401,558,559],{},"Далее речь пойдёт о ребрах с положительными весами.",[424,561,563],{"id":562},"история-одного-обмена","История одного обмена",[401,565,566],{},"Рассмотрим конкретный пример. Допустим вы хотите поменять свою книгу на планшет.\nЧтобы успешно произвести такой обмен, необходимо понять как потратить наименьшую сумму по цепочке обменов.\nДопустим у нас есть некоторые предложения от других людей. Изобразим выдуманный пример в виде графа:",[401,568,569],{},[434,570],{"alt":571,"src":572},"Пример взвешенного графа обмена","/images/blog/python/st32/img_4.png",[401,574,575],{},"Узлы графа – это предметы, на которые можно поменяться. Веса рёбер представляют сумму доплаты за обмен.\nТаким образом, можно поменять картину на гитару за 300 рублей или же куртку на гитару за 150 рублей(условные суммы).",[401,577,578],{},"Как нам вычислить путь от книги до планшета, при котором потратиться наименьшая сумма?\nНа помощь приходит алгоритм Дейкстры! Выполним все 4 шага алгоритма и в конце вычислим итоговый путь по графу.\nПрежде чем начинать, необходимо построить таблицу со стоимостями всех узлов. Таблица будет обновляться по мере работы алгоритма.",[401,580,581],{},[434,582],{"alt":583,"src":584},"Таблица взвешенного графа обмена","/images/blog/python/st32/img_5.png",[401,586,587],{},"Для вычисления итогового пути добавляется столбец – родитель. Итак, приступим к выполнению алгоритма:",[401,589,590,592],{},[419,591,461],{}," найти узел с наименьшей стоимостью. В данном случае самый дешёвый вариант обмена с доплатой 0 рублей это картина.\nВозможно ли получить картину с меньшими затратами?\nЭто очень важный момент.\nУдастся ли найти серию обменов, при которой мы получим картину менее чем за 0 рублей(точнее нам ещё заплатят)?\nПравильный ответ: в данном графе это не удастся.\nТак как картина это узел с наименьшей стоимостью, до которого можно добраться и снизить его заданную стоимость нельзя.\nВ этом заключается суть и идея алгоритма Дейкстры: в графе ищется всегда путь с наименьшей стоимостью.\nПути к этому с картиной с меньшими затратами не существует!",[401,594,595,597],{},[419,596,470],{}," вычислить, сколько времени потребуется для того, чтобы добраться до всех соседей(стоимость).",[401,599,600],{},[434,601],{"alt":602,"src":603},"Пример взвешенного графа обмена: 2 шага","/images/blog/python/st32/img_6.png",[401,605,606],{},"Стоимости гитары и барабана заносятся в таблицу.\nОни были заданы при переходе через узел картины, поэтому картина указывается как их родитель.\nЭто означает, что для того, чтобы добраться до гитары, вы проходите по ребру от картины; то же самое происходит с барабаном.",[401,608,609],{},[434,610],{"alt":611,"src":612},"Таблица взвешенного графа обмена: 2 шага","/images/blog/python/st32/img_7.png",[401,614,615,618],{},[419,616,617],{},"Снова шаг 1:"," куртка – следующий по стоимости узел(50 рублей).",[401,620,621,624],{},[419,622,623],{},"Снова шаг 2:"," обновляются значения всех его соседей.",[401,626,627,631],{},[434,628],{"alt":629,"src":630},"Пример взвешенного графа обмена: 4 шага","/images/blog/python/st32/img_8.png",[434,632],{"alt":633,"src":634},"Пример взвешенного таблицы обмена: 4 шага","/images/blog/python/st32/img_9.png",[401,636,637],{},"Смотрите, стоимости барабана и гитары обновились!\nЭто означает, что к барабану и гитаре дешевле перейти через ребро, идущее от куртки.\nСоответственно, куртка назначается новым родителем обоих инструментов.",[401,639,640],{},"Следующий по стоимости узел – гитара. Обновите данные его соседей.",[401,642,643,647],{},[434,644],{"alt":645,"src":646},"Пример взвешенного графа обмена: 6 шагов","/images/blog/python/st32/img_10.png",[434,648],{"alt":649,"src":650},"Пример взвешенного таблицы обмена: 6 шагов","/images/blog/python/st32/img_11.png",[401,652,653],{},"Наконец-то мы вычислили стоимость для планшета при условии обмена гитары на планшет.\nСоответственно, гитара назначается родителем.\nНаконец, задается стоимость последнего узла – барабана.",[401,655,656,660],{},[434,657],{"alt":658,"src":659},"Пример взвешенного графа обмена: 8 шагов","/images/blog/python/st32/img_12.png",[434,661],{"alt":662,"src":663},"Пример взвешенного таблицы обмена: 8 шагов","/images/blog/python/st32/img_13.png",[401,665,666],{},"Оказывается, вы можете получить планшет дешевле, поменяв барабан на планшет.\nТаким образом, самая дешёвая цепочка обменов обойдётся в 350 рублей.",[401,668,669],{},"Теперь, осталось вычислить итоговый путь.\nК этому моменту мы(алгоритм) знаем, что кратчайший путь обойдётся в 350 рублей, но как этот путь определить?",[401,671,672],{},"Для начала возьмём родителя для узла \"планшет\".\nВ качестве родителя узла \"планшет\" указан узел \"барабан\".\nА в качестве родителя узла \"барабан\" указан узел \"куртка\".\nСледовательно, вы обмениваете куртку на барабан. И конечно, в самом начале вы меняете книгу на куртку.\nПроходя по родительским узлам в обратном направлении получается полный путь:",[401,674,675],{},[434,676],{"alt":677,"src":678},"Пример взвешенного графа обмена: полный путь","/images/blog/python/st32/img_14.png",[401,680,681],{},"Целью этого примера было показать, что кратчайший путь не всегда связывается с физическим расстоянием:\nон может решать задачу минимизации какой-либо характеристики благодаря тому же алгоритму Дейкстры!",[424,683,685],{"id":684},"рёбра-с-отрицательным-весом","Рёбра с отрицательным весом",[401,687,688],{},"Изменим пример выше. Предположим, что существует обмен куртки на картину и при этом вам ещё заплатят 70 рублей.\nВы ничего не тратите при таком обмене, вместо этого вы наоборот получаете!\nИзобразим это на графе:",[401,690,691],{},[434,692],{"alt":693,"src":694},"Пример взвешенного графа обмена: с отрицательным ребром","/images/blog/python/st32/img_15.png",[401,696,697],{},"Ребро, ведущее от куртки к картине, имеет отрицательный вес! Получается также, что к картине можно добраться двумя способами.\nА значит что на обмене с отрицательным весом(когда платите не вы, а вам) появляется смысл – вы получите ещё 20 рублей от начальной суммы.\nТеперь, если вы помните, вы можете обменять картину на барабан. И до этого обмена существуют два пути:\nВторой путь обойдётся на 20 рублей дешевле, поэтому нужно выбрать этот путь.\nНо если применить алгоритм Дейкстры к этому графе, то алгоритм выберет неверный путь!\nАлгоритм пойдёт по более длинному пути.\nАлгоритм Дейкстры не может использоваться при наличии рёбер, имеющих отрицательный вес.\nТакие рёбра нарушают работу алгоритма Дейкстры. Посмотрим на пример: начиная с таблицы стоимостей.",[401,699,700],{},[434,701],{"alt":702,"src":703},"Пример таблицы обмена: для графа с отрицательным ребром","/images/blog/python/st32/img_16.png",[401,705,706],{},"Теперь найдём узел с наименьшей стоимостью и обновим стоимости его соседей.\nВ этом случае картина оказывается узлом с наименьшей стоимостью.\nВ соответствии с алгоритмом Дейкстры, к картине невозможно перейти более дешёвым способом, чем обменом её на вашу книгу(а видя весь граф вы знаете что это неверно!).\nКак бы то ни было, продолжая пример обновим стоимости соседей картины.",[401,708,709],{},[434,710],{"alt":711,"src":712},"Пример таблицы обмена: для графа с отрицательным ребром 2 шага","/images/blog/python/st32/img_17.png",[401,714,715],{},"Получается, что теперь стоимость барабана составляет 350 рублей.\nПерейдём к следующему по стоимости узлу, который ещё не был обработан – это куртка. Обновим стоимости её соседей.",[401,717,718],{},[434,719],{"alt":720,"src":721},"Пример таблицы обмена: для графа с отрицательным ребром 4 шага","/images/blog/python/st32/img_18.png",[401,723,724],{},"Узел \"картина\" уже был обработан, однако алгоритм обновляет его стоимость.\nЭто очень плохой признак – обработка узла означает, что к нему невозможно добраться с меньшими затратами.\nНо вы самостоятельно уже нашли более \"дешёвый\" путь к картине.\nУ барабана соседей нет, поэтому работа алгоритма завершается.\nНиже покажем итоговые стоимости согласно алгоритму Дейкстры:",[401,726,727],{},[434,728],{"alt":729,"src":730},"Пример таблицы обмена: для графа с отрицательным ребром итог","/images/blog/python/st32/img_19.png",[401,732,733,734,740,741,747],{},"Чтобы добраться до барабана, вам потребовалось 350 рублей.\nВы знаете, что существует путь, который стоит всего 330 рублей, но алгоритм Дейкстры его не находит.\nАлгоритм Дейкстры сразу предположил, что, поскольку вы обрабатываете узел \"картина\", к этому узлу невозможно добраться быстрее!\nЭто предположение работает только в том случае, если рёбер с отрицательным весом не существует.\nСледовательно, ",[735,736,737],"strong",{},[419,738,739],{},"использование алгоритма Дейкстры с графом, содержащим рёбра с отрицательным весом — невозможно",".\nВ случае с отрицательными весами понадобится алгоритм ",[405,742,746],{"href":743,"rel":744},"https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BB%D0%BB%D0%BC%D0%B0%D0%BD%D0%B0_%E2%80%94_%D0%A4%D0%BE%D1%80%D0%B4%D0%B0",[745],"nofollow","Беллмана — Форда",".\nРассмотрение алгоритма Беллмана — Форда выходит за рамки этой статьи.\nЗаймёмся теперь реализацией алгоритма Дейкстры.",[424,749,751],{"id":750},"реализация-алгоритма-дейкстры","Реализация алгоритма Дейкстры",[401,753,754],{},"Ниже изображён граф, который будет использоваться в примере с кодом:",[401,756,757],{},[434,758],{"alt":759,"src":760},"Пример взвешенного графа: реализация","/images/blog/python/st32/img_20.png",[401,762,763],{},"Для реализации понадобятся три хеш-таблицы или три словаря в Python.\nСловари стоимостей и родителей будут обновляться по ходу работы алгоритма.\nСначала необходимо реализовать словарь для графа:",[765,766,771],"pre",{"className":767,"code":768,"language":769,"meta":770,"style":770},"language-python shiki shiki-themes github-light","graph = {}\n","python","",[772,773,774],"code",{"__ignoreMap":770},[775,776,779,783,787],"span",{"class":777,"line":778},"line",1,[775,780,782],{"class":781},"sgsFI","graph ",[775,784,786],{"class":785},"sD7c4","=",[775,788,789],{"class":781}," {}\n",[401,791,792],{},"Необходимо сохранить соседей и стоимость перехода. Судя по графу у начального узла есть два соседа, A и B.\nВеса рёбер графа также представим виде хеш-таблицы или словаря:",[765,794,796],{"className":767,"code":795,"language":769,"meta":770,"style":770},"graph[\"start\"] = {}\ngraph[\"start\"][\"a\"] = 6\ngraph[\"start\"][\"b\"] = 2\n",[772,797,798,814,835],{"__ignoreMap":770},[775,799,800,803,807,810,812],{"class":777,"line":778},[775,801,802],{"class":781},"graph[",[775,804,806],{"class":805},"sYBdl","\"start\"",[775,808,809],{"class":781},"] ",[775,811,786],{"class":785},[775,813,789],{"class":781},[775,815,817,819,821,824,827,829,831],{"class":777,"line":816},2,[775,818,802],{"class":781},[775,820,806],{"class":805},[775,822,823],{"class":781},"][",[775,825,826],{"class":805},"\"a\"",[775,828,809],{"class":781},[775,830,786],{"class":785},[775,832,834],{"class":833},"sYu0t"," 6\n",[775,836,838,840,842,844,847,849,851],{"class":777,"line":837},3,[775,839,802],{"class":781},[775,841,806],{"class":805},[775,843,823],{"class":781},[775,845,846],{"class":805},"\"b\"",[775,848,809],{"class":781},[775,850,786],{"class":785},[775,852,853],{"class":833}," 2\n",[401,855,856,857,860],{},"Итак, ",[772,858,859],{},"graph[\"start\"]"," является словарём. Для получения всех соседей узла можно воспользоваться следующим выражением:",[765,862,864],{"className":767,"code":863,"language":769,"meta":770,"style":770},"print(list(graph[\"start\"].keys()))\n# [\"a\", \"b\"]\n",[772,865,866,885],{"__ignoreMap":770},[775,867,868,871,874,877,880,882],{"class":777,"line":778},[775,869,870],{"class":833},"print",[775,872,873],{"class":781},"(",[775,875,876],{"class":833},"list",[775,878,879],{"class":781},"(graph[",[775,881,806],{"class":805},[775,883,884],{"class":781},"].keys()))\n",[775,886,887],{"class":777,"line":816},[775,888,890],{"class":889},"sAwPA","# [\"a\", \"b\"]\n",[401,892,893],{},"Одно ребро ведёт из начального узла в A, а другое из начального узла в B. Веса узнать этих рёбер можно так:",[765,895,897],{"className":767,"code":896,"language":769,"meta":770,"style":770},"print(graph[\"start\"][\"a\"]) # 6\nprint(graph[\"start\"][\"b\"]) # 2\n",[772,898,899,917],{"__ignoreMap":770},[775,900,901,903,905,907,909,911,914],{"class":777,"line":778},[775,902,870],{"class":833},[775,904,879],{"class":781},[775,906,806],{"class":805},[775,908,823],{"class":781},[775,910,826],{"class":805},[775,912,913],{"class":781},"]) ",[775,915,916],{"class":889},"# 6\n",[775,918,919,921,923,925,927,929,931],{"class":777,"line":816},[775,920,870],{"class":833},[775,922,879],{"class":781},[775,924,806],{"class":805},[775,926,823],{"class":781},[775,928,846],{"class":805},[775,930,913],{"class":781},[775,932,933],{"class":889},"# 2\n",[401,935,936],{},"Допишем в граф остальные узлы:",[765,938,940],{"className":767,"code":939,"language":769,"meta":770,"style":770},"graph[\"a\"] = {}\ngraph[\"a\"][\"final\"] = 1\ngraph[\"b\"] = {}\ngraph[\"b\"][\"a\"] = 3\ngraph[\"b\"][\"final\"] = 5\ngraph[\"final\"] = {}  # У конечного узла соседей нет\n",[772,941,942,954,972,984,1002,1020],{"__ignoreMap":770},[775,943,944,946,948,950,952],{"class":777,"line":778},[775,945,802],{"class":781},[775,947,826],{"class":805},[775,949,809],{"class":781},[775,951,786],{"class":785},[775,953,789],{"class":781},[775,955,956,958,960,962,965,967,969],{"class":777,"line":816},[775,957,802],{"class":781},[775,959,826],{"class":805},[775,961,823],{"class":781},[775,963,964],{"class":805},"\"final\"",[775,966,809],{"class":781},[775,968,786],{"class":785},[775,970,971],{"class":833}," 1\n",[775,973,974,976,978,980,982],{"class":777,"line":837},[775,975,802],{"class":781},[775,977,846],{"class":805},[775,979,809],{"class":781},[775,981,786],{"class":785},[775,983,789],{"class":781},[775,985,987,989,991,993,995,997,999],{"class":777,"line":986},4,[775,988,802],{"class":781},[775,990,846],{"class":805},[775,992,823],{"class":781},[775,994,826],{"class":805},[775,996,809],{"class":781},[775,998,786],{"class":785},[775,1000,1001],{"class":833}," 3\n",[775,1003,1005,1007,1009,1011,1013,1015,1017],{"class":777,"line":1004},5,[775,1006,802],{"class":781},[775,1008,846],{"class":805},[775,1010,823],{"class":781},[775,1012,964],{"class":805},[775,1014,809],{"class":781},[775,1016,786],{"class":785},[775,1018,1019],{"class":833}," 5\n",[775,1021,1023,1025,1027,1029,1031,1034],{"class":777,"line":1022},6,[775,1024,802],{"class":781},[775,1026,964],{"class":805},[775,1028,809],{"class":781},[775,1030,786],{"class":785},[775,1032,1033],{"class":781}," {}  ",[775,1035,1036],{"class":889},"# У конечного узла соседей нет\n",[401,1038,1039,1040,1043],{},"Стоимость узла определяет, сколько времени потребуется для перехода к этому узлу от начального узла.\nВы не знаете, сколько времени потребуется для достижения конечного узла. Если стоимость ещё неизвестна, она считается бесконечной.\nКак представить бесконечно в Python? Есть следующий вариант: ",[772,1041,1042],{},"infinity = math.inf",".\nКод создания словаря стоимостей:",[765,1045,1047],{"className":767,"code":1046,"language":769,"meta":770,"style":770},"import math\ninfinity = math.inf\ncosts = {}\ncosts[\"a\"] = 6\ncosts[\"b\"] = 2\ncosts[\"final\"] = infinity\n",[772,1048,1049,1057,1067,1076,1089,1101],{"__ignoreMap":770},[775,1050,1051,1054],{"class":777,"line":778},[775,1052,1053],{"class":785},"import",[775,1055,1056],{"class":781}," math\n",[775,1058,1059,1062,1064],{"class":777,"line":816},[775,1060,1061],{"class":781},"infinity ",[775,1063,786],{"class":785},[775,1065,1066],{"class":781}," math.inf\n",[775,1068,1069,1072,1074],{"class":777,"line":837},[775,1070,1071],{"class":781},"costs ",[775,1073,786],{"class":785},[775,1075,789],{"class":781},[775,1077,1078,1081,1083,1085,1087],{"class":777,"line":986},[775,1079,1080],{"class":781},"costs[",[775,1082,826],{"class":805},[775,1084,809],{"class":781},[775,1086,786],{"class":785},[775,1088,834],{"class":833},[775,1090,1091,1093,1095,1097,1099],{"class":777,"line":1004},[775,1092,1080],{"class":781},[775,1094,846],{"class":805},[775,1096,809],{"class":781},[775,1098,786],{"class":785},[775,1100,853],{"class":833},[775,1102,1103,1105,1107,1109,1111],{"class":777,"line":1022},[775,1104,1080],{"class":781},[775,1106,964],{"class":805},[775,1108,809],{"class":781},[775,1110,786],{"class":785},[775,1112,1113],{"class":781}," infinity\n",[401,1115,1116],{},"Для родителей также создадим отдельный словарь. Код представлен ниже:",[765,1118,1120],{"className":767,"code":1119,"language":769,"meta":770,"style":770},"parents = {}\nparents[\"a\"] = \"start\"\nparents[\"b\"] = \"start\"\nparents[\"final\"] = None\n",[772,1121,1122,1131,1145,1157],{"__ignoreMap":770},[775,1123,1124,1127,1129],{"class":777,"line":778},[775,1125,1126],{"class":781},"parents ",[775,1128,786],{"class":785},[775,1130,789],{"class":781},[775,1132,1133,1136,1138,1140,1142],{"class":777,"line":816},[775,1134,1135],{"class":781},"parents[",[775,1137,826],{"class":805},[775,1139,809],{"class":781},[775,1141,786],{"class":785},[775,1143,1144],{"class":805}," \"start\"\n",[775,1146,1147,1149,1151,1153,1155],{"class":777,"line":837},[775,1148,1135],{"class":781},[775,1150,846],{"class":805},[775,1152,809],{"class":781},[775,1154,786],{"class":785},[775,1156,1144],{"class":805},[775,1158,1159,1161,1163,1165,1167],{"class":777,"line":986},[775,1160,1135],{"class":781},[775,1162,964],{"class":805},[775,1164,809],{"class":781},[775,1166,786],{"class":785},[775,1168,1169],{"class":833}," None\n",[401,1171,1172],{},"Наконец, нужно множество для отслеживания всех уже обработанных узлов, так как один узел не должен обрабатываться многократно:",[765,1174,1176],{"className":767,"code":1175,"language":769,"meta":770,"style":770},"processed = set()\n",[772,1177,1178],{"__ignoreMap":770},[775,1179,1180,1183,1185,1188],{"class":777,"line":778},[775,1181,1182],{"class":781},"processed ",[775,1184,786],{"class":785},[775,1186,1187],{"class":833}," set",[775,1189,1190],{"class":781},"()\n",[401,1192,1193],{},"На этом подготовка для данных завершена. Ниже напишем код алгоритма:",[765,1195,1197],{"className":767,"code":1196,"language":769,"meta":770,"style":770},"node = find_lowest_cost(costs) # Найти узел с наименьшей стоимостью среди необработанных\nwhile node is not None: # Обрабатываем все узлы\n  cost = costs[node] # Получить стоимость\n  neighbors = graph[node] # Получить соседей узла\n  for n in neighbors.keys(): # Перебор всех соседей текущего узла\n    new_cost = cost + neighbors[n] # Вычисляем стоимость пути перехода\n    if costs[n] > new_cost: # Если к соседу можно добрать быстрее через текущий узел\n      costs[n] = new_cost # Обновить стоимость узла\n      parents[n] = node # Этот узел становится новым родителем для соседа\n  processed.add(node) # Узел помечается как обработанный\n  node = find_lowest_cost(costs) # Найти следующий узел для обработки\n",[772,1198,1199,1212,1235,1248,1261,1278,1297,1315,1329,1342,1351],{"__ignoreMap":770},[775,1200,1201,1204,1206,1209],{"class":777,"line":778},[775,1202,1203],{"class":781},"node ",[775,1205,786],{"class":785},[775,1207,1208],{"class":781}," find_lowest_cost(costs) ",[775,1210,1211],{"class":889},"# Найти узел с наименьшей стоимостью среди необработанных\n",[775,1213,1214,1217,1220,1223,1226,1229,1232],{"class":777,"line":816},[775,1215,1216],{"class":785},"while",[775,1218,1219],{"class":781}," node ",[775,1221,1222],{"class":785},"is",[775,1224,1225],{"class":785}," not",[775,1227,1228],{"class":833}," None",[775,1230,1231],{"class":781},": ",[775,1233,1234],{"class":889},"# Обрабатываем все узлы\n",[775,1236,1237,1240,1242,1245],{"class":777,"line":837},[775,1238,1239],{"class":781},"  cost ",[775,1241,786],{"class":785},[775,1243,1244],{"class":781}," costs[node] ",[775,1246,1247],{"class":889},"# Получить стоимость\n",[775,1249,1250,1253,1255,1258],{"class":777,"line":986},[775,1251,1252],{"class":781},"  neighbors ",[775,1254,786],{"class":785},[775,1256,1257],{"class":781}," graph[node] ",[775,1259,1260],{"class":889},"# Получить соседей узла\n",[775,1262,1263,1266,1269,1272,1275],{"class":777,"line":1004},[775,1264,1265],{"class":785},"  for",[775,1267,1268],{"class":781}," n ",[775,1270,1271],{"class":785},"in",[775,1273,1274],{"class":781}," neighbors.keys(): ",[775,1276,1277],{"class":889},"# Перебор всех соседей текущего узла\n",[775,1279,1280,1283,1285,1288,1291,1294],{"class":777,"line":1022},[775,1281,1282],{"class":781},"    new_cost ",[775,1284,786],{"class":785},[775,1286,1287],{"class":781}," cost ",[775,1289,1290],{"class":785},"+",[775,1292,1293],{"class":781}," neighbors[n] ",[775,1295,1296],{"class":889},"# Вычисляем стоимость пути перехода\n",[775,1298,1300,1303,1306,1309,1312],{"class":777,"line":1299},7,[775,1301,1302],{"class":785},"    if",[775,1304,1305],{"class":781}," costs[n] ",[775,1307,1308],{"class":785},">",[775,1310,1311],{"class":781}," new_cost: ",[775,1313,1314],{"class":889},"# Если к соседу можно добрать быстрее через текущий узел\n",[775,1316,1318,1321,1323,1326],{"class":777,"line":1317},8,[775,1319,1320],{"class":781},"      costs[n] ",[775,1322,786],{"class":785},[775,1324,1325],{"class":781}," new_cost ",[775,1327,1328],{"class":889},"# Обновить стоимость узла\n",[775,1330,1332,1335,1337,1339],{"class":777,"line":1331},9,[775,1333,1334],{"class":781},"      parents[n] ",[775,1336,786],{"class":785},[775,1338,1219],{"class":781},[775,1340,1341],{"class":889},"# Этот узел становится новым родителем для соседа\n",[775,1343,1345,1348],{"class":777,"line":1344},10,[775,1346,1347],{"class":781},"  processed.add(node) ",[775,1349,1350],{"class":889},"# Узел помечается как обработанный\n",[775,1352,1354,1357,1359,1361],{"class":777,"line":1353},11,[775,1355,1356],{"class":781},"  node ",[775,1358,786],{"class":785},[775,1360,1208],{"class":781},[775,1362,1363],{"class":889},"# Найти следующий узел для обработки\n",[401,1365,1366,1367,1370],{},"После того как все узлы будут обработаны, алгоритм завершается. Код функции ",[772,1368,1369],{},"find_lowest_cost(costs)"," приведём ниже:",[765,1372,1374],{"className":767,"code":1373,"language":769,"meta":770,"style":770},"def find_lowest_cost(costs):\n  lowest_cost = math.inf\n  lowest_cost_node = None\n  for node in costs: # Перебираем все узлы\n    cost = costs[node]\n    if cost \u003C lowest_cost and node not in processed: # Если узел с наименьшей стоимость и ещё не был обработан\n      lowest_cost = cost # он назначается новым узлом с наименьшей стоимостью\n      lowest_cost_node = node\n  return lowest_cost_node\n",[772,1375,1376,1388,1397,1406,1420,1430,1459,1471,1481],{"__ignoreMap":770},[775,1377,1378,1381,1385],{"class":777,"line":778},[775,1379,1380],{"class":785},"def",[775,1382,1384],{"class":1383},"s7eDp"," find_lowest_cost",[775,1386,1387],{"class":781},"(costs):\n",[775,1389,1390,1393,1395],{"class":777,"line":816},[775,1391,1392],{"class":781},"  lowest_cost ",[775,1394,786],{"class":785},[775,1396,1066],{"class":781},[775,1398,1399,1402,1404],{"class":777,"line":837},[775,1400,1401],{"class":781},"  lowest_cost_node ",[775,1403,786],{"class":785},[775,1405,1169],{"class":833},[775,1407,1408,1410,1412,1414,1417],{"class":777,"line":986},[775,1409,1265],{"class":785},[775,1411,1219],{"class":781},[775,1413,1271],{"class":785},[775,1415,1416],{"class":781}," costs: ",[775,1418,1419],{"class":889},"# Перебираем все узлы\n",[775,1421,1422,1425,1427],{"class":777,"line":1004},[775,1423,1424],{"class":781},"    cost ",[775,1426,786],{"class":785},[775,1428,1429],{"class":781}," costs[node]\n",[775,1431,1432,1434,1436,1439,1442,1445,1447,1450,1453,1456],{"class":777,"line":1022},[775,1433,1302],{"class":785},[775,1435,1287],{"class":781},[775,1437,1438],{"class":785},"\u003C",[775,1440,1441],{"class":781}," lowest_cost ",[775,1443,1444],{"class":785},"and",[775,1446,1219],{"class":781},[775,1448,1449],{"class":785},"not",[775,1451,1452],{"class":785}," in",[775,1454,1455],{"class":781}," processed: ",[775,1457,1458],{"class":889},"# Если узел с наименьшей стоимость и ещё не был обработан\n",[775,1460,1461,1464,1466,1468],{"class":777,"line":1299},[775,1462,1463],{"class":781},"      lowest_cost ",[775,1465,786],{"class":785},[775,1467,1287],{"class":781},[775,1469,1470],{"class":889},"# он назначается новым узлом с наименьшей стоимостью\n",[775,1472,1473,1476,1478],{"class":777,"line":1317},[775,1474,1475],{"class":781},"      lowest_cost_node ",[775,1477,786],{"class":785},[775,1479,1480],{"class":781}," node\n",[775,1482,1483,1486],{"class":777,"line":1331},[775,1484,1485],{"class":785},"  return",[775,1487,1488],{"class":781}," lowest_cost_node\n",[401,1490,1491],{},"Чтобы найти узел с наименьшей стоимостью, мы каждый раз перебираем все узлы. Существует более эффективный вариант этого алгоритма.\nОн использует структуру данных, называемую очередью с приоритетом. Эта очередь строится на основе другой структуры данных — кучи.\nЕсли вам интересны очереди с приоритетом и кучи, об этом будет далее статья.",[401,1493,1494],{},"Объединим весь код:",[765,1496,1498],{"className":767,"code":1497,"language":769,"meta":770,"style":770},"import math\n\ngraph = {}\ngraph[\"start\"] = {}\ngraph[\"start\"][\"a\"] = 6\ngraph[\"start\"][\"b\"] = 2\ngraph[\"a\"] = {}\ngraph[\"a\"][\"final\"] = 1\ngraph[\"b\"] = {}\ngraph[\"b\"][\"a\"] = 3\ngraph[\"b\"][\"final\"] = 5\ngraph[\"final\"] = {}\n\ninfinity = math.inf\ncosts = {}\ncosts[\"a\"] = 6\ncosts[\"b\"] = 2\ncosts[\"final\"] = infinity\n\nparents = {}\nparents[\"a\"] = \"start\"\nparents[\"b\"] = \"start\"\nparents[\"final\"] = None\n\nprocessed = set()\n\ndef find_lowest_cost(costs):\n  lowest_cost = math.inf\n  lowest_cost_node = None\n  for node in costs:\n    cost = costs[node]\n    if cost \u003C lowest_cost and node not in processed:\n      lowest_cost = cost\n      lowest_cost_node = node\n  return lowest_cost_node\n\nnode = find_lowest_cost(costs)\nwhile node is not None:\n  cost = costs[node]\n  neighbors = graph[node]\n  for n in neighbors.keys():\n    new_cost = cost + neighbors[n]\n    if costs[n] > new_cost:\n      costs[n] = new_cost\n      parents[n] = node\n  processed.add(node)\n  node = find_lowest_cost(costs)\n\nprint(\"Стоимость от начала до каждого узла:\")\nprint(costs)\n",[772,1499,1500,1506,1512,1520,1532,1548,1564,1576,1592,1604,1620,1636,1649,1654,1663,1672,1685,1698,1711,1716,1725,1738,1751,1764,1769,1780,1785,1794,1803,1812,1824,1833,1855,1865,1874,1881,1886,1896,1912,1921,1931,1943,1957,1969,1979,1988,1994,2003,2008,2021],{"__ignoreMap":770},[775,1501,1502,1504],{"class":777,"line":778},[775,1503,1053],{"class":785},[775,1505,1056],{"class":781},[775,1507,1508],{"class":777,"line":816},[775,1509,1511],{"emptyLinePlaceholder":1510},true,"\n",[775,1513,1514,1516,1518],{"class":777,"line":837},[775,1515,782],{"class":781},[775,1517,786],{"class":785},[775,1519,789],{"class":781},[775,1521,1522,1524,1526,1528,1530],{"class":777,"line":986},[775,1523,802],{"class":781},[775,1525,806],{"class":805},[775,1527,809],{"class":781},[775,1529,786],{"class":785},[775,1531,789],{"class":781},[775,1533,1534,1536,1538,1540,1542,1544,1546],{"class":777,"line":1004},[775,1535,802],{"class":781},[775,1537,806],{"class":805},[775,1539,823],{"class":781},[775,1541,826],{"class":805},[775,1543,809],{"class":781},[775,1545,786],{"class":785},[775,1547,834],{"class":833},[775,1549,1550,1552,1554,1556,1558,1560,1562],{"class":777,"line":1022},[775,1551,802],{"class":781},[775,1553,806],{"class":805},[775,1555,823],{"class":781},[775,1557,846],{"class":805},[775,1559,809],{"class":781},[775,1561,786],{"class":785},[775,1563,853],{"class":833},[775,1565,1566,1568,1570,1572,1574],{"class":777,"line":1299},[775,1567,802],{"class":781},[775,1569,826],{"class":805},[775,1571,809],{"class":781},[775,1573,786],{"class":785},[775,1575,789],{"class":781},[775,1577,1578,1580,1582,1584,1586,1588,1590],{"class":777,"line":1317},[775,1579,802],{"class":781},[775,1581,826],{"class":805},[775,1583,823],{"class":781},[775,1585,964],{"class":805},[775,1587,809],{"class":781},[775,1589,786],{"class":785},[775,1591,971],{"class":833},[775,1593,1594,1596,1598,1600,1602],{"class":777,"line":1331},[775,1595,802],{"class":781},[775,1597,846],{"class":805},[775,1599,809],{"class":781},[775,1601,786],{"class":785},[775,1603,789],{"class":781},[775,1605,1606,1608,1610,1612,1614,1616,1618],{"class":777,"line":1344},[775,1607,802],{"class":781},[775,1609,846],{"class":805},[775,1611,823],{"class":781},[775,1613,826],{"class":805},[775,1615,809],{"class":781},[775,1617,786],{"class":785},[775,1619,1001],{"class":833},[775,1621,1622,1624,1626,1628,1630,1632,1634],{"class":777,"line":1353},[775,1623,802],{"class":781},[775,1625,846],{"class":805},[775,1627,823],{"class":781},[775,1629,964],{"class":805},[775,1631,809],{"class":781},[775,1633,786],{"class":785},[775,1635,1019],{"class":833},[775,1637,1639,1641,1643,1645,1647],{"class":777,"line":1638},12,[775,1640,802],{"class":781},[775,1642,964],{"class":805},[775,1644,809],{"class":781},[775,1646,786],{"class":785},[775,1648,789],{"class":781},[775,1650,1652],{"class":777,"line":1651},13,[775,1653,1511],{"emptyLinePlaceholder":1510},[775,1655,1657,1659,1661],{"class":777,"line":1656},14,[775,1658,1061],{"class":781},[775,1660,786],{"class":785},[775,1662,1066],{"class":781},[775,1664,1666,1668,1670],{"class":777,"line":1665},15,[775,1667,1071],{"class":781},[775,1669,786],{"class":785},[775,1671,789],{"class":781},[775,1673,1675,1677,1679,1681,1683],{"class":777,"line":1674},16,[775,1676,1080],{"class":781},[775,1678,826],{"class":805},[775,1680,809],{"class":781},[775,1682,786],{"class":785},[775,1684,834],{"class":833},[775,1686,1688,1690,1692,1694,1696],{"class":777,"line":1687},17,[775,1689,1080],{"class":781},[775,1691,846],{"class":805},[775,1693,809],{"class":781},[775,1695,786],{"class":785},[775,1697,853],{"class":833},[775,1699,1701,1703,1705,1707,1709],{"class":777,"line":1700},18,[775,1702,1080],{"class":781},[775,1704,964],{"class":805},[775,1706,809],{"class":781},[775,1708,786],{"class":785},[775,1710,1113],{"class":781},[775,1712,1714],{"class":777,"line":1713},19,[775,1715,1511],{"emptyLinePlaceholder":1510},[775,1717,1719,1721,1723],{"class":777,"line":1718},20,[775,1720,1126],{"class":781},[775,1722,786],{"class":785},[775,1724,789],{"class":781},[775,1726,1728,1730,1732,1734,1736],{"class":777,"line":1727},21,[775,1729,1135],{"class":781},[775,1731,826],{"class":805},[775,1733,809],{"class":781},[775,1735,786],{"class":785},[775,1737,1144],{"class":805},[775,1739,1741,1743,1745,1747,1749],{"class":777,"line":1740},22,[775,1742,1135],{"class":781},[775,1744,846],{"class":805},[775,1746,809],{"class":781},[775,1748,786],{"class":785},[775,1750,1144],{"class":805},[775,1752,1754,1756,1758,1760,1762],{"class":777,"line":1753},23,[775,1755,1135],{"class":781},[775,1757,964],{"class":805},[775,1759,809],{"class":781},[775,1761,786],{"class":785},[775,1763,1169],{"class":833},[775,1765,1767],{"class":777,"line":1766},24,[775,1768,1511],{"emptyLinePlaceholder":1510},[775,1770,1772,1774,1776,1778],{"class":777,"line":1771},25,[775,1773,1182],{"class":781},[775,1775,786],{"class":785},[775,1777,1187],{"class":833},[775,1779,1190],{"class":781},[775,1781,1783],{"class":777,"line":1782},26,[775,1784,1511],{"emptyLinePlaceholder":1510},[775,1786,1788,1790,1792],{"class":777,"line":1787},27,[775,1789,1380],{"class":785},[775,1791,1384],{"class":1383},[775,1793,1387],{"class":781},[775,1795,1797,1799,1801],{"class":777,"line":1796},28,[775,1798,1392],{"class":781},[775,1800,786],{"class":785},[775,1802,1066],{"class":781},[775,1804,1806,1808,1810],{"class":777,"line":1805},29,[775,1807,1401],{"class":781},[775,1809,786],{"class":785},[775,1811,1169],{"class":833},[775,1813,1815,1817,1819,1821],{"class":777,"line":1814},30,[775,1816,1265],{"class":785},[775,1818,1219],{"class":781},[775,1820,1271],{"class":785},[775,1822,1823],{"class":781}," costs:\n",[775,1825,1827,1829,1831],{"class":777,"line":1826},31,[775,1828,1424],{"class":781},[775,1830,786],{"class":785},[775,1832,1429],{"class":781},[775,1834,1836,1838,1840,1842,1844,1846,1848,1850,1852],{"class":777,"line":1835},32,[775,1837,1302],{"class":785},[775,1839,1287],{"class":781},[775,1841,1438],{"class":785},[775,1843,1441],{"class":781},[775,1845,1444],{"class":785},[775,1847,1219],{"class":781},[775,1849,1449],{"class":785},[775,1851,1452],{"class":785},[775,1853,1854],{"class":781}," processed:\n",[775,1856,1858,1860,1862],{"class":777,"line":1857},33,[775,1859,1463],{"class":781},[775,1861,786],{"class":785},[775,1863,1864],{"class":781}," cost\n",[775,1866,1868,1870,1872],{"class":777,"line":1867},34,[775,1869,1475],{"class":781},[775,1871,786],{"class":785},[775,1873,1480],{"class":781},[775,1875,1877,1879],{"class":777,"line":1876},35,[775,1878,1485],{"class":785},[775,1880,1488],{"class":781},[775,1882,1884],{"class":777,"line":1883},36,[775,1885,1511],{"emptyLinePlaceholder":1510},[775,1887,1889,1891,1893],{"class":777,"line":1888},37,[775,1890,1203],{"class":781},[775,1892,786],{"class":785},[775,1894,1895],{"class":781}," find_lowest_cost(costs)\n",[775,1897,1899,1901,1903,1905,1907,1909],{"class":777,"line":1898},38,[775,1900,1216],{"class":785},[775,1902,1219],{"class":781},[775,1904,1222],{"class":785},[775,1906,1225],{"class":785},[775,1908,1228],{"class":833},[775,1910,1911],{"class":781},":\n",[775,1913,1915,1917,1919],{"class":777,"line":1914},39,[775,1916,1239],{"class":781},[775,1918,786],{"class":785},[775,1920,1429],{"class":781},[775,1922,1924,1926,1928],{"class":777,"line":1923},40,[775,1925,1252],{"class":781},[775,1927,786],{"class":785},[775,1929,1930],{"class":781}," graph[node]\n",[775,1932,1934,1936,1938,1940],{"class":777,"line":1933},41,[775,1935,1265],{"class":785},[775,1937,1268],{"class":781},[775,1939,1271],{"class":785},[775,1941,1942],{"class":781}," neighbors.keys():\n",[775,1944,1946,1948,1950,1952,1954],{"class":777,"line":1945},42,[775,1947,1282],{"class":781},[775,1949,786],{"class":785},[775,1951,1287],{"class":781},[775,1953,1290],{"class":785},[775,1955,1956],{"class":781}," neighbors[n]\n",[775,1958,1960,1962,1964,1966],{"class":777,"line":1959},43,[775,1961,1302],{"class":785},[775,1963,1305],{"class":781},[775,1965,1308],{"class":785},[775,1967,1968],{"class":781}," new_cost:\n",[775,1970,1972,1974,1976],{"class":777,"line":1971},44,[775,1973,1320],{"class":781},[775,1975,786],{"class":785},[775,1977,1978],{"class":781}," new_cost\n",[775,1980,1982,1984,1986],{"class":777,"line":1981},45,[775,1983,1334],{"class":781},[775,1985,786],{"class":785},[775,1987,1480],{"class":781},[775,1989,1991],{"class":777,"line":1990},46,[775,1992,1993],{"class":781},"  processed.add(node)\n",[775,1995,1997,1999,2001],{"class":777,"line":1996},47,[775,1998,1356],{"class":781},[775,2000,786],{"class":785},[775,2002,1895],{"class":781},[775,2004,2006],{"class":777,"line":2005},48,[775,2007,1511],{"emptyLinePlaceholder":1510},[775,2009,2011,2013,2015,2018],{"class":777,"line":2010},49,[775,2012,870],{"class":833},[775,2014,873],{"class":781},[775,2016,2017],{"class":805},"\"Стоимость от начала до каждого узла:\"",[775,2019,2020],{"class":781},")\n",[775,2022,2024,2026],{"class":777,"line":2023},50,[775,2025,870],{"class":833},[775,2027,2028],{"class":781},"(costs)\n",[398,2030,2031],{},[401,2032,2033,2034,422],{},"В следующей статье информация про ",[405,2035,2036],{"href":295},"жадные алгоритмы",[2038,2039],"h4",{"id":770},[393,2041],{":isList":2042,"title":2043},"[\"Поиск в ширину вычисляет кратчайший путь в невзвешенном графе;\",\"Алгоритм Дейкстры вычисляет кратчайший путь во взвешенном графе;\",\"Алгоритм Дейкстры работает только в том случае, если все веса положительны;\",\"При наличии отрицательных весов используйте алгоритм Беллмана – Форда.\"]","ШПАРГАЛКА",[401,2045,2046,2047,2050,2051,2054],{},"Попробуйте сами скопировать и запустить код в окне ниже с интерпретатором Python и повторите примеры из статьи чтобы самим увидеть и понять как всё это работает.\nДля этого в ячейке с кодом нажмите клавиши на клавиатуре ",[735,2048,2049],{},"Shift+Enter"," или запустите код через ",[735,2052,2053],{},"кнопку Run"," по значку ▶.",[2056,2057],"jypiter",{},[2059,2060,2061],"style",{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}",{"title":770,"searchDepth":816,"depth":1004,"links":2063},[2064],{"id":391,"depth":816,"text":290,"children":2065},[2066,2067,2068,2069,2070],{"id":426,"depth":837,"text":427},{"id":526,"depth":837,"text":527},{"id":562,"depth":837,"text":563},{"id":684,"depth":837,"text":685},{"id":750,"depth":837,"text":751,"children":2071},[2072],{"id":770,"depth":986,"text":770},"2026-04-16T00:00:00.000Z","Взвешенные графы. Поиск кратчайшего пути.","md","images/blog/python/st32/img.png",{},{"title":290,"description":2074},"zsjWm7Vgd0tOLdAvLs6qYLRqIG3RUFhEV5C2u1J7hzY",[2081,2083],{"title":286,"path":287,"stem":288,"description":2082,"children":-1},"Бинарное дерево поиска. Сбалансированные деревья. АВЛ-деревья. B-деревья.",{"title":294,"path":295,"stem":296,"description":2084,"children":-1},"Жадная стратегия при решении задач. NP-трудные задачи. Приближенное решение NP-полных задач.",1777359499040]