[{"data":1,"prerenderedAt":8041},["ShallowReactive",2],{"navigation":3,"blog-page":386,"blog-blogs":531},[4],{"title":5,"path":6,"stem":7,"children":8,"page":114},"Blog","\u002Fblog","blog",[9,115,184,329],{"title":10,"path":11,"stem":12,"children":13,"page":114},"Ege","\u002Fblog\u002Fege","blog\u002Fege",[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","\u002Fblog\u002Fege\u002Ftask1","blog\u002Fege\u002Ftask1",{"title":19,"path":20,"stem":21},"ЕГЭ Задание 10","\u002Fblog\u002Fege\u002Ftask10","blog\u002Fege\u002Ftask10",{"title":23,"path":24,"stem":25},"ЕГЭ Задание 11","\u002Fblog\u002Fege\u002Ftask11","blog\u002Fege\u002Ftask11",{"title":27,"path":28,"stem":29},"ЕГЭ Задание 12","\u002Fblog\u002Fege\u002Ftask12","blog\u002Fege\u002Ftask12",{"title":31,"path":32,"stem":33},"ЕГЭ Задание 13","\u002Fblog\u002Fege\u002Ftask13","blog\u002Fege\u002Ftask13",{"title":35,"path":36,"stem":37},"ЕГЭ Задание 14","\u002Fblog\u002Fege\u002Ftask14","blog\u002Fege\u002Ftask14",{"title":39,"path":40,"stem":41},"ЕГЭ Задание 15","\u002Fblog\u002Fege\u002Ftask15","blog\u002Fege\u002Ftask15",{"title":43,"path":44,"stem":45},"ЕГЭ Задание 16","\u002Fblog\u002Fege\u002Ftask16","blog\u002Fege\u002Ftask16",{"title":47,"path":48,"stem":49},"ЕГЭ Задание 17","\u002Fblog\u002Fege\u002Ftask17","blog\u002Fege\u002Ftask17",{"title":51,"path":52,"stem":53},"ЕГЭ Задание 18","\u002Fblog\u002Fege\u002Ftask18","blog\u002Fege\u002Ftask18",{"title":55,"path":56,"stem":57},"ЕГЭ Задание 19, 20, 21","\u002Fblog\u002Fege\u002Ftask19_20_21","blog\u002Fege\u002Ftask19_20_21",{"title":59,"path":60,"stem":61},"ЕГЭ Задание 2","\u002Fblog\u002Fege\u002Ftask2","blog\u002Fege\u002Ftask2",{"title":63,"path":64,"stem":65},"ЕГЭ Задание 22","\u002Fblog\u002Fege\u002Ftask22","blog\u002Fege\u002Ftask22",{"title":67,"path":68,"stem":69},"ЕГЭ Задание 23","\u002Fblog\u002Fege\u002Ftask23","blog\u002Fege\u002Ftask23",{"title":71,"path":72,"stem":73},"ЕГЭ Задание 24","\u002Fblog\u002Fege\u002Ftask24","blog\u002Fege\u002Ftask24",{"title":75,"path":76,"stem":77},"ЕГЭ Задание 25","\u002Fblog\u002Fege\u002Ftask25","blog\u002Fege\u002Ftask25",{"title":79,"path":80,"stem":81},"ЕГЭ Задание 26","\u002Fblog\u002Fege\u002Ftask26","blog\u002Fege\u002Ftask26",{"title":83,"path":84,"stem":85},"ЕГЭ Задание 27","\u002Fblog\u002Fege\u002Ftask27","blog\u002Fege\u002Ftask27",{"title":87,"path":88,"stem":89},"ЕГЭ Задание 3","\u002Fblog\u002Fege\u002Ftask3","blog\u002Fege\u002Ftask3",{"title":91,"path":92,"stem":93},"ЕГЭ Задание 4","\u002Fblog\u002Fege\u002Ftask4","blog\u002Fege\u002Ftask4",{"title":95,"path":96,"stem":97},"ЕГЭ Задание 5","\u002Fblog\u002Fege\u002Ftask5","blog\u002Fege\u002Ftask5",{"title":99,"path":100,"stem":101},"ЕГЭ Задание 6","\u002Fblog\u002Fege\u002Ftask6","blog\u002Fege\u002Ftask6",{"title":103,"path":104,"stem":105},"ЕГЭ Задание 7","\u002Fblog\u002Fege\u002Ftask7","blog\u002Fege\u002Ftask7",{"title":107,"path":108,"stem":109},"ЕГЭ Задание 8","\u002Fblog\u002Fege\u002Ftask8","blog\u002Fege\u002Ftask8",{"title":111,"path":112,"stem":113},"ЕГЭ Задание 9","\u002Fblog\u002Fege\u002Ftask9","blog\u002Fege\u002Ftask9",false,{"title":116,"path":117,"stem":118,"children":119,"page":114},"Oge","\u002Fblog\u002Foge","blog\u002Foge",[120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180],{"title":121,"path":122,"stem":123},"ОГЭ Задание 1","\u002Fblog\u002Foge\u002Ftask1","blog\u002Foge\u002Ftask1",{"title":125,"path":126,"stem":127},"ОГЭ Задание 10","\u002Fblog\u002Foge\u002Ftask10","blog\u002Foge\u002Ftask10",{"title":129,"path":130,"stem":131},"ОГЭ Задание 11","\u002Fblog\u002Foge\u002Ftask11","blog\u002Foge\u002Ftask11",{"title":133,"path":134,"stem":135},"ОГЭ Задание 12","\u002Fblog\u002Foge\u002Ftask12","blog\u002Foge\u002Ftask12",{"title":137,"path":138,"stem":139},"ОГЭ Задание 13","\u002Fblog\u002Foge\u002Ftask13","blog\u002Foge\u002Ftask13",{"title":141,"path":142,"stem":143},"ОГЭ Задание 14","\u002Fblog\u002Foge\u002Ftask14","blog\u002Foge\u002Ftask14",{"title":145,"path":146,"stem":147},"ОГЭ Задание 15","\u002Fblog\u002Foge\u002Ftask15","blog\u002Foge\u002Ftask15",{"title":149,"path":150,"stem":151},"ОГЭ Задание 16","\u002Fblog\u002Foge\u002Ftask16","blog\u002Foge\u002Ftask16",{"title":153,"path":154,"stem":155},"ОГЭ Задание 2","\u002Fblog\u002Foge\u002Ftask2","blog\u002Foge\u002Ftask2",{"title":157,"path":158,"stem":159},"ОГЭ Задание 3","\u002Fblog\u002Foge\u002Ftask3","blog\u002Foge\u002Ftask3",{"title":161,"path":162,"stem":163},"ОГЭ Задание 4","\u002Fblog\u002Foge\u002Ftask4","blog\u002Foge\u002Ftask4",{"title":165,"path":166,"stem":167},"ОГЭ Задание 5","\u002Fblog\u002Foge\u002Ftask5","blog\u002Foge\u002Ftask5",{"title":169,"path":170,"stem":171},"ОГЭ Задание 6","\u002Fblog\u002Foge\u002Ftask6","blog\u002Foge\u002Ftask6",{"title":173,"path":174,"stem":175},"ОГЭ Задание 7","\u002Fblog\u002Foge\u002Ftask7","blog\u002Foge\u002Ftask7",{"title":177,"path":178,"stem":179},"ОГЭ Задание 8","\u002Fblog\u002Foge\u002Ftask8","blog\u002Foge\u002Ftask8",{"title":181,"path":182,"stem":183},"ОГЭ Задание 9","\u002Fblog\u002Foge\u002Ftask9","blog\u002Foge\u002Ftask9",{"title":185,"path":186,"stem":187,"children":188,"page":114},"Python","\u002Fblog\u002Fpython","blog\u002Fpython",[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,321,325],{"title":190,"path":191,"stem":192},"Знакомство с синтаксисом","\u002Fblog\u002Fpython\u002Fst1","blog\u002Fpython\u002Fst1",{"title":194,"path":195,"stem":196},"Отладка","\u002Fblog\u002Fpython\u002Fst10","blog\u002Fpython\u002Fst10",{"title":198,"path":199,"stem":200},"Модули и пакеты","\u002Fblog\u002Fpython\u002Fst11","blog\u002Fpython\u002Fst11",{"title":202,"path":203,"stem":204},"Кортежи","\u002Fblog\u002Fpython\u002Fst12","blog\u002Fpython\u002Fst12",{"title":206,"path":207,"stem":208},"Знакомство со списками","\u002Fblog\u002Fpython\u002Fst13","blog\u002Fpython\u002Fst13",{"title":210,"path":211,"stem":212},"Списки и циклы","\u002Fblog\u002Fpython\u002Fst14","blog\u002Fpython\u002Fst14",{"title":214,"path":215,"stem":216},"Использование списков ч.1","\u002Fblog\u002Fpython\u002Fst15","blog\u002Fpython\u002Fst15",{"title":218,"path":219,"stem":220},"Использование списков ч.2","\u002Fblog\u002Fpython\u002Fst16","blog\u002Fpython\u002Fst16",{"title":222,"path":223,"stem":224},"Использование списков ч.3","\u002Fblog\u002Fpython\u002Fst17","blog\u002Fpython\u002Fst17",{"title":226,"path":227,"stem":228},"Словари","\u002Fblog\u002Fpython\u002Fst18","blog\u002Fpython\u002Fst18",{"title":230,"path":231,"stem":232},"Множества","\u002Fblog\u002Fpython\u002Fst19","blog\u002Fpython\u002Fst19",{"title":234,"path":235,"stem":236},"Переменные","\u002Fblog\u002Fpython\u002Fst2","blog\u002Fpython\u002Fst2",{"title":238,"path":239,"stem":240},"Хеш-таблицы","\u002Fblog\u002Fpython\u002Fst20","blog\u002Fpython\u002Fst20",{"title":242,"path":243,"stem":244},"Решето Эратосфена","\u002Fblog\u002Fpython\u002Fst21","blog\u002Fpython\u002Fst21",{"title":246,"path":247,"stem":248},"Длинная арифметика","\u002Fblog\u002Fpython\u002Fst22","blog\u002Fpython\u002Fst22",{"title":250,"path":251,"stem":252},"Декораторы функций","\u002Fblog\u002Fpython\u002Fst23","blog\u002Fpython\u002Fst23",{"title":254,"path":255,"stem":256},"Знакомство с алгоритмами","\u002Fblog\u002Fpython\u002Fst24","blog\u002Fpython\u002Fst24",{"title":258,"path":259,"stem":260},"Бинарный поиск – примеры задач","\u002Fblog\u002Fpython\u002Fst25","blog\u002Fpython\u002Fst25",{"title":262,"path":263,"stem":264},"Сортировка выбором","\u002Fblog\u002Fpython\u002Fst26","blog\u002Fpython\u002Fst26",{"title":266,"path":267,"stem":268},"Рекурсия и стек","\u002Fblog\u002Fpython\u002Fst27","blog\u002Fpython\u002Fst27",{"title":270,"path":271,"stem":272},"Быстрая сортировка","\u002Fblog\u002Fpython\u002Fst28","blog\u002Fpython\u002Fst28",{"title":274,"path":275,"stem":276},"Поиск в ширину","\u002Fblog\u002Fpython\u002Fst29","blog\u002Fpython\u002Fst29",{"title":278,"path":279,"stem":280},"Работа со строками","\u002Fblog\u002Fpython\u002Fst3","blog\u002Fpython\u002Fst3",{"title":282,"path":283,"stem":284},"Поиск в глубину","\u002Fblog\u002Fpython\u002Fst30","blog\u002Fpython\u002Fst30",{"title":286,"path":287,"stem":288},"Сбалансированные деревья","\u002Fblog\u002Fpython\u002Fst31","blog\u002Fpython\u002Fst31",{"title":290,"path":291,"stem":292},"Алгоритм Дейкстры","\u002Fblog\u002Fpython\u002Fst32","blog\u002Fpython\u002Fst32",{"title":294,"path":295,"stem":296},"Жадные алгоритмы","\u002Fblog\u002Fpython\u002Fst33","blog\u002Fpython\u002Fst33",{"title":298,"path":299,"stem":300},"Динамическое программирование","\u002Fblog\u002Fpython\u002Fst34","blog\u002Fpython\u002Fst34",{"title":302,"path":303,"stem":304},"Алгоритм k ближайших соседей","\u002Fblog\u002Fpython\u002Fst35","blog\u002Fpython\u002Fst35",{"title":306,"path":307,"stem":308},"Типы данных","\u002Fblog\u002Fpython\u002Fst4","blog\u002Fpython\u002Fst4",{"title":310,"path":311,"stem":312},"О функциях","\u002Fblog\u002Fpython\u002Fst5","blog\u002Fpython\u002Fst5",{"title":314,"path":315,"stem":316},"Свойства и методы","\u002Fblog\u002Fpython\u002Fst6","blog\u002Fpython\u002Fst6",{"title":318,"path":319,"stem":320},"Определение функций","\u002Fblog\u002Fpython\u002Fst7","blog\u002Fpython\u002Fst7",{"title":322,"path":323,"stem":324},"Логика","\u002Fblog\u002Fpython\u002Fst8","blog\u002Fpython\u002Fst8",{"title":326,"path":327,"stem":328},"Циклы","\u002Fblog\u002Fpython\u002Fst9","blog\u002Fpython\u002Fst9",{"title":330,"path":331,"stem":332,"children":333,"page":114},"Toi","\u002Fblog\u002Ftoi","blog\u002Ftoi",[334,338,342,346,350,354,358,362,366,370,374,378,382],{"title":335,"path":336,"stem":337},"Информация и информационные процессы","\u002Fblog\u002Ftoi\u002Fst1","blog\u002Ftoi\u002Fst1",{"title":339,"path":340,"stem":341},"Электронные таблицы","\u002Fblog\u002Ftoi\u002Fst10","blog\u002Ftoi\u002Fst10",{"title":343,"path":344,"stem":345},"Система, её свойства и компоненты. Моделирование","\u002Fblog\u002Ftoi\u002Fst11","blog\u002Ftoi\u002Fst11",{"title":347,"path":348,"stem":349},"Представление информации в компьютере","\u002Fblog\u002Ftoi\u002Fst12","blog\u002Ftoi\u002Fst12",{"title":351,"path":352,"stem":353},"Средства информационно-коммуникационных технологий. Файловая система","\u002Fblog\u002Ftoi\u002Fst13","blog\u002Ftoi\u002Fst13",{"title":355,"path":356,"stem":357},"Комбинаторика","\u002Fblog\u002Ftoi\u002Fst2","blog\u002Ftoi\u002Fst2",{"title":359,"path":360,"stem":361},"Адресация в интернете","\u002Fblog\u002Ftoi\u002Fst3","blog\u002Ftoi\u002Fst3",{"title":363,"path":364,"stem":365},"Измерение количества информации","\u002Fblog\u002Ftoi\u002Fst4","blog\u002Ftoi\u002Fst4",{"title":367,"path":368,"stem":369},"Системы счисления","\u002Fblog\u002Ftoi\u002Fst5","blog\u002Ftoi\u002Fst5",{"title":371,"path":372,"stem":373},"Диаграммы Эйлера — Венна","\u002Fblog\u002Ftoi\u002Fst6","blog\u002Ftoi\u002Fst6",{"title":375,"path":376,"stem":377},"Условие Фано","\u002Fblog\u002Ftoi\u002Fst7","blog\u002Ftoi\u002Fst7",{"title":379,"path":380,"stem":381},"Теория графов","\u002Fblog\u002Ftoi\u002Fst8","blog\u002Ftoi\u002Fst8",{"title":383,"path":384,"stem":385},"Алгебра логики","\u002Fblog\u002Ftoi\u002Fst9","blog\u002Ftoi\u002Fst9",{"id":387,"title":388,"about":389,"blog":392,"body":395,"description":396,"experience":397,"extension":439,"faq":440,"hero":479,"meta":512,"navigation":513,"path":514,"seo":515,"stem":518,"testimonials":519,"__hash__":530},"index\u002Findex.yml","Привет, Я Альберт Игоревич учитель информатики и FullStack разработчик.",{"title":390,"description":391},"Обо мне","Как учитель и разработчик с 10-летним опытом работы, я использую свою степень магистра и преподавателя исследователя Белгородского государственного университета.\nМой подход сочетает творческую стратегию с техническими знаниями, превращая концепции в функциональные, целенаправленные цифровые продукты и решения, которые органично сочетают дизайн и технологии.\n",{"title":393,"description":394},"Блог","Последние статьи на сайте",null,"Я обучаю информатике и информационным технологиям, а также создаю интуитивно понятные цифровые решения, в которых функциональность сочетается с дизайном. Я живу в Белгороде и воплощаю идеи в жизнь с помощью кода и креатива.",{"title":398,"items":399},"Опыт работы",[400,407,414,421,425,432],{"position":401,"date":402,"company":403},"Учитель","2022 - ...",{"name":404,"url":405,"color":406},"Формула Успеха","https:\u002F\u002Fformula.gosuslugi.ru\u002F","#0000ff",{"position":408,"date":409,"company":410},"Лаборант","2020 - 2021",{"name":411,"url":412,"color":413},"НИУ БелГУ","https:\u002F\u002Fbsuedu.ru\u002Fbsu\u002F","#144F16",{"position":415,"date":416,"company":417},"Программист","2019 - 2020",{"name":418,"url":419,"color":420},"Нефтегазметрология","https:\u002F\u002Foilgm.ru\u002F","#1e5374",{"position":422,"date":423,"company":424},"Инженер КИПиА","2018",{"name":411,"url":412,"color":413},{"position":426,"date":427,"company":428},"Диспетчер ПДО","2016 - 2017",{"name":429,"url":430,"color":431},"ЗАО Сокол-АТС","https:\u002F\u002Fwww.sokol-ats.ru","#302958",{"position":433,"date":434,"company":435},"Оператор","2015",{"name":436,"url":437,"color":438},"АО \"ЗВЕЗДА-ЭНЕРГЕТИКА\"","https:\u002F\u002Fwww.zvec.ru","#a41e1f","yml",{"title":441,"description":442,"categories":443},"Часто задаваемые вопросы","Ответы на распространенные вопросы о моем процессе и услугах.",[444,456,471],{"title":445,"questions":446},"Услуги",[447,450,453],{"label":448,"content":449},"Какие услуги вы предлагаете?","Я специализируюсь на обучении информатики\u002Fпрограммирования на Python и fullstack разработке. Это включает в себя обучение учащихся для сдачи единого государственного экзамена ОГЭ\u002FЕГЭ по информатике. В области разработки это \"скрапинг и парсинг\" данных, интерактивное прототипирование, создание интуитивно понятных пользовательских интерфейсов, создание адаптивных приложений, веб-сайтов и веб-приложений. Моя цель – успешное обучение учащихся для сдачи экзаменов и создание цифровых продуктов от разработки концепции до внедрения.\n",{"label":451,"content":452},"Почему стоит пользоваться вашими услугами?","Мой процесс является совместным и итеративным и обычно включает в себя такие этапы, как поиск и исследование, формирование идей, прототипирование, разработка, проверка и тестирование, визуальный контакт и тесное сотрудничество. Я адаптирую процесс в соответствии с потребностями и всегда уделяя особое внимание решениям, ориентированным на конечного пользователя моих услуг.\n",{"label":454,"content":455},"Вы работаете с новичками?","Конечно! Мне нравится работать с начинающими, помогая им формировать знания в области программирования и учить создавать решения с нуля. Я могу адаптировать свой процесс к быстро меняющейся среде обучения.\n",{"title":457,"questions":458},"Цена и сроки",[459,462,465,468],{"label":460,"content":461},"Сколько обычно стоит ваша услуга?","Стоимость проекта варьируется в зависимости от объема, сложности, функций и сроков реализации. Стоимость комплексных проектов по Разработке, как правило, составляет от 30000 рублей, а средние проекты варьируются от 40000 до 100000 рублей. За консультации или выполнение конкретных задач моя дневная ставка составляет 1000-1500 рублей.\n",{"label":463,"content":464},"Каковы ваши условия оплаты?","Как правило, для планирования проекта и начала работы мне требуется внести предоплату в размере 40%, а оставшиеся 60% выплачиваются после успешного завершения проекта и сдачи его в эксплуатацию. Я принимаю платежи банковским переводом.\n",{"label":466,"content":467},"Сколько времени занимает проект или обучение?","Сроки сильно зависят от масштаба и сложности проекта\u002Fобучения. На выполнение небольших проектов\u002Fобучения может уйти 3-4 недели, в то время как на выполнение более крупных проектов\u002Fобучения или с большим количеством участников может уйти от 2 до 12 месяцев. Я всегда предоставляю подробную оценку сроков после первоначального этапа исследования сложности проекта\u002Fобучения.\n",{"label":469,"content":470},"Предоставляете ли вы постоянную поддержку?","Да, для клиентов, нуждающихся в постоянной поддержке, разработке функциональных возможностей или техническом обслуживании, я предлагаю варианты ежемесячной оплаты с учетом конкретных потребностей. Давайте обсудим, что конкретно вас интересует.\n",{"title":390,"questions":472},[473,476],{"label":474,"content":475},"Что вам больше всего нравится в вашей работе?","Мне нравится решать сложные задачи с помощью обучения и технологий. Невероятно приятно видеть, как люди взаимодействуют с тем, что я создал или чему научил, и находят это действительно полезным. Мне по-настоящему нравится преодолевать разрыв между потребностями и техническими возможностями.\n",{"label":477,"content":478},"Чем вы увлекаетесь вне работы?","Вне профессиональной деятельности я люблю играть на гитаре или отправляться на рыбалку.\n",{"links":480,"images":484},[481],{"label":482,"to":405,"color":483},"Тавровская СОШ \"Формула Успеха\"","info",[485,488,491,494,497,500,503,506,509],{"src":486,"alt":487},"\u002Fhero\u002Frandom-1.avif","Random Image 1",{"src":489,"alt":490},"\u002Fhero\u002Frandom-2.avif","Random Image 2",{"src":492,"alt":493},"\u002Fhero\u002Frandom-3.avif","Random Image 3",{"src":495,"alt":496},"\u002Fhero\u002Frandom-4.avif","Random Image 4",{"src":498,"alt":499},"\u002Fhero\u002Frandom-5.avif","Random Image 5",{"src":501,"alt":502},"\u002Fhero\u002Frandom-6.avif","Random Image 6",{"src":504,"alt":505},"\u002Fhero\u002Frandom-7.avif","Random Image 7",{"src":507,"alt":508},"\u002Fhero\u002Frandom-8.avif","Random Image 8",{"src":510,"alt":511},"\u002Fhero\u002Frandom-9.avif","Random Image 9",{},true,"\u002F",{"title":516,"description":517},"Штана Альберт Игоревич","Я Альберт Игоревич, учитель информатики и FullStack разработчик из Белгорода. Я специализируюсь на обучении информатики и создании красивых и функциональных цифровых приложений, ориентированных на пользователя.","index",[520,523,526],{"quote":521,"description":411,"src":522,"srcset":522},"Диплом аспиранта","\u002Fimages\u002Fdocuments\u002Fdiplom_aspirant.jpg",{"quote":524,"description":411,"src":525,"srcset":525},"Диплом магистра","\u002Fimages\u002Fdocuments\u002Fdiplom_magister.jpg",{"quote":527,"description":528,"src":529,"srcset":529},"Диплом специалиста","БГТУ им.Шухова","\u002Fimages\u002Fdocuments\u002Fdiplom_specialist.jpg","0vV30edgVQDtugcASJVUViv-oZ8JQonUojckakiLUEU",[532,1490,4636,6026,7632],{"id":533,"title":302,"author":534,"body":538,"date":1482,"description":1483,"extension":1484,"image":1485,"meta":1486,"minRead":785,"navigation":513,"num":1487,"path":303,"seo":1488,"stem":304,"__hash__":1489},"blog\u002Fblog\u002Fpython\u002Fst35.md",{"name":516,"avatar":535},{"src":536,"alt":537},"me.jpg","@ashtana",{"type":539,"value":540,"toc":1442},"minimark",[541,545,550,562,565,570,573,578,969,974,977,980,983,991,995,998,1056,1059,1069,1072,1083,1086,1089,1098,1102,1105,1113,1116,1119,1124,1129,1132,1136,1139,1142,1151,1154,1158,1161,1165,1168,1172,1175,1194,1197,1202,1205,1209,1213,1216,1220,1223,1234,1237,1243,1246,1250,1253,1257,1266,1270,1288,1308,1311,1315,1318,1322,1329,1333,1336,1344,1347,1351,1354,1358,1361,1364,1367,1378,1381,1385,1398,1412,1416,1426,1430,1433,1438],[542,543,302],"h2",{"id":544},"алгоритм-k-ближайших-соседей",[546,547],"card-collapsible",{":isList":548,"title":549},"[\"Научитесь строить системы классификации на базе алгоритма k ближайших соседей.\",\"Узнаете об извлечении признаков.\",\"Узнаете о регрессии: прогнозировании чисел (например, завтрашних биржевых котировок или успеха фильма у зрителей).\",\"Познакомитесь с типичными сценариями использования и ограничениями алгоритма k ближайших соседей.\"]","Из этой статьи вы",[551,552,553],"blockquote",{},[554,555,556,557,561],"p",{},"В предыдущей статье было про: ",[558,559,560],"a",{"href":299},"динамическое программирование",".\nЗдесь далее текст пойдёт об алгоритме k ближайших соседей.",[554,563,564],{},"Алгоритм k ближайших соседей прост и полезен! Если вы пытаетесь выполнить классификацию чего-либо, сначала попробуйте применить алгоритм k ближайших соседей.\nРассмотрим реалистичный пример.",[566,567,569],"h4",{"id":568},"построение-рекомендательной-системы","Построение рекомендательной системы",[554,571,572],{},"Представьте, что вы работаете с сайтом о кино и хотите построить систему, которая будет рекомендовать фильмы для ваших пользователей.\nПоложение пользователя определяется его вкусами, поэтому пользователи с похожими вкусами располагаются недалеко друг от друга.\nПредположим, вы хотите порекомендовать фильмы Алексею. Найдите 5 пользователей, ближайших к нему.\nДопустим, окажется, что у Ивана, Сергея, Анны, Ларисы и Анатолия похожие вкусы.\nЗначит, те фильмы, которые нравятся им, с большой вероятностью понравятся и Алексею!\nПосле того как у вас появится такая диаграмма, построить рекомендательную систему будет несложно.\nЕсли Анатолию нравится какой-нибудь фильм, порекомендуйте этот фильм Алексею.\nОднако в картине не хватает одного важного фрагмента.\nВы сравнивали вкусы двух пользователей. Но как определить, насколько они близки?",[574,575,577],"h5",{"id":576},"извлечение-признаков","Извлечение признаков",[554,579,580,581,788,789,968],{},"В примере с фруктами можно сравнивать фрукты на основании их размера и цвета кожуры.\nРазмер и цвет — признаки, по которым ведется сравнение.\nТеперь предположим, что у вас есть три фрукта.\nВы можете извлечь из них информацию, то есть провести извлечение признаков.\nДанные этих фруктов наносятся на график.\nПредположим, что из диаграммы хорошо видно, что фрукты A и B похожи.\nДавайте измерим степень их сходства.\nДля вычисления расстояния между двумя точками применяется формула Пифагора: ",[582,583,587],"mjx-container",{"className":584,"jax":586},[585],"MathJax","SVG",[588,589,598,638],"svg",{"style":590,"xmlns":591,"width":592,"height":593,"role":594,"focusable":595,"viewBox":596,"xmlnsXLink":597},"vertical-align: -1.094ex;","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","24.857ex","4.208ex","img","false","0 -1376.5 10986.7 1860","http:\u002F\u002Fwww.w3.org\u002F1999\u002Fxlink",[599,600,601,606,610,614,618,622,626,630,634],"defs",{},[602,603],"path",{"id":604,"d":605},"MJX-1-TEX-LO-221A","M1001 1150Q1017 1150 1020 1132Q1020 1127 741 244L460 -643Q453 -650 436 -650H424Q423 -647 423 -645T421 -640T419 -631T415 -617T408 -594T399 -560T385 -512T367 -448T343 -364T312 -259L203 119L138 41L111 67L212 188L264 248L472 -474L983 1140Q988 1150 1001 1150Z",[602,607],{"id":608,"d":609},"MJX-1-TEX-N-28","M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z",[602,611],{"id":612,"d":613},"MJX-1-TEX-I-1D465","M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z",[602,615],{"id":616,"d":617},"MJX-1-TEX-N-31","M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z",[602,619],{"id":620,"d":621},"MJX-1-TEX-N-2212","M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z",[602,623],{"id":624,"d":625},"MJX-1-TEX-N-32","M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z",[602,627],{"id":628,"d":629},"MJX-1-TEX-N-29","M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z",[602,631],{"id":632,"d":633},"MJX-1-TEX-N-2B","M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z",[602,635],{"id":636,"d":637},"MJX-1-TEX-I-1D466","M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z",[639,640,644],"g",{"stroke":641,"fill":641,"stroke-width":642,"transform":643},"currentColor","0","scale(1,-1)",[639,645,647],{"dataMmlNode":646},"math",[639,648,650,774,781],{"dataMmlNode":649},"msqrt",[639,651,653,719,726],{"transform":652},"translate(1020,0)",[639,654,656,714],{"dataMmlNode":655},"msup",[639,657,660,668,687,694,707],{"dataMmlNode":658,"dataMjxTexclass":659},"TeXAtom","ORD",[639,661,663],{"dataMmlNode":662},"mo",[664,665],"use",{"dataC":666,"xLinkHref":667},"28","#MJX-1-TEX-N-28",[639,669,672,679],{"dataMmlNode":670,"transform":671},"msub","translate(389,0)",[639,673,675],{"dataMmlNode":674},"mi",[664,676],{"dataC":677,"xLinkHref":678},"1D465","#MJX-1-TEX-I-1D465",[639,680,683],{"dataMmlNode":681,"transform":682},"mn","translate(605,-150) scale(0.707)",[664,684],{"dataC":685,"xLinkHref":686},"31","#MJX-1-TEX-N-31",[639,688,690],{"dataMmlNode":662,"transform":689},"translate(1619.8,0)",[664,691],{"dataC":692,"xLinkHref":693},"2212","#MJX-1-TEX-N-2212",[639,695,697,701],{"dataMmlNode":670,"transform":696},"translate(2620,0)",[639,698,699],{"dataMmlNode":674},[664,700],{"dataC":677,"xLinkHref":678},[639,702,703],{"dataMmlNode":681,"transform":682},[664,704],{"dataC":705,"xLinkHref":706},"32","#MJX-1-TEX-N-32",[639,708,710],{"dataMmlNode":662,"transform":709},"translate(3628.6,0)",[664,711],{"dataC":712,"xLinkHref":713},"29","#MJX-1-TEX-N-29",[639,715,717],{"dataMmlNode":681,"transform":716},"translate(4050.6,477.1) scale(0.707)",[664,718],{"dataC":705,"xLinkHref":706},[639,720,722],{"dataMmlNode":662,"transform":721},"translate(4676.3,0)",[664,723],{"dataC":724,"xLinkHref":725},"2B","#MJX-1-TEX-N-2B",[639,727,729,769],{"dataMmlNode":655,"transform":728},"translate(5676.5,0)",[639,730,731,735,748,753,764],{"dataMmlNode":658,"dataMjxTexclass":659},[639,732,733],{"dataMmlNode":662},[664,734],{"dataC":666,"xLinkHref":667},[639,736,737,743],{"dataMmlNode":670,"transform":671},[639,738,739],{"dataMmlNode":674},[664,740],{"dataC":741,"xLinkHref":742},"1D466","#MJX-1-TEX-I-1D466",[639,744,746],{"dataMmlNode":681,"transform":745},"translate(523,-150) scale(0.707)",[664,747],{"dataC":685,"xLinkHref":686},[639,749,751],{"dataMmlNode":662,"transform":750},"translate(1537.8,0)",[664,752],{"dataC":692,"xLinkHref":693},[639,754,756,760],{"dataMmlNode":670,"transform":755},"translate(2538,0)",[639,757,758],{"dataMmlNode":674},[664,759],{"dataC":741,"xLinkHref":742},[639,761,762],{"dataMmlNode":681,"transform":745},[664,763],{"dataC":705,"xLinkHref":706},[639,765,767],{"dataMmlNode":662,"transform":766},"translate(3464.6,0)",[664,768],{"dataC":712,"xLinkHref":713},[639,770,772],{"dataMmlNode":681,"transform":771},"translate(3886.6,477.1) scale(0.707)",[664,773],{"dataC":705,"xLinkHref":706},[639,775,777],{"dataMmlNode":662,"transform":776},"translate(0,166.5)",[664,778],{"dataC":779,"xLinkHref":780},"221A","#MJX-1-TEX-LO-221A",[782,783],"rect",{"width":784,"height":785,"x":786,"y":787},9966.7,60,"1020","1256.5","\nФормула расстояния подтверждает то, что мы видим: между фруктами есть или отсутствует сходство.\nДопустим, вместо фруктов вы сравниваете пользователей. Пользователей нужно будет как-то нанести на график.\nСледовательно, каждого пользователя нужно будет преобразовать в координаты.\nКогда вы сможете нанести пользователей на график, вы также сможете измерить расстояние между ними.\nНачнем с преобразования пользователей в набор чисел.\nКогда пользователь регистрируется на сайте, предложите ему оценить несколько категорий фильмов: нравятся они лично ему или нет.\nТаким образом у вас появляется набор оценок для каждого пользователя!\nИ в итоге каждый пользователь представляется набором из чисел.\nВместо вычисления расстояния в двух измерениях вы теперь вычисляете расстояние в n измерениях(зависит от категорий жанров у фильмов).\nТем не менее формула расстояния остается неизменной:\n",[582,790,792],{"className":791,"jax":586},[585],[588,793,796,830],{"style":590,"xmlns":591,"width":794,"height":593,"role":594,"focusable":595,"viewBox":795,"xmlnsXLink":597},"29.127ex","0 -1376.5 12874.2 1860",[599,797,798,801,804,807,810,813,816,819,822,826],{},[602,799],{"id":800,"d":605},"MJX-2-TEX-LO-221A",[602,802],{"id":803,"d":609},"MJX-2-TEX-N-28",[602,805],{"id":806,"d":613},"MJX-2-TEX-I-1D465",[602,808],{"id":809,"d":617},"MJX-2-TEX-N-31",[602,811],{"id":812,"d":621},"MJX-2-TEX-N-2212",[602,814],{"id":815,"d":625},"MJX-2-TEX-N-32",[602,817],{"id":818,"d":629},"MJX-2-TEX-N-29",[602,820],{"id":821,"d":633},"MJX-2-TEX-N-2B",[602,823],{"id":824,"d":825},"MJX-2-TEX-N-2E","M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60Z",[602,827],{"id":828,"d":829},"MJX-2-TEX-I-1D45B","M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z",[639,831,832],{"stroke":641,"fill":641,"stroke-width":642,"transform":643},[639,833,834],{"dataMmlNode":646},[639,835,836,960,965],{"dataMmlNode":649},[639,837,838,884,890,897,902,907,912],{"transform":652},[639,839,840,880],{"dataMmlNode":655},[639,841,842,847,859,864,875],{"dataMmlNode":658,"dataMjxTexclass":659},[639,843,844],{"dataMmlNode":662},[664,845],{"dataC":666,"xLinkHref":846},"#MJX-2-TEX-N-28",[639,848,849,854],{"dataMmlNode":670,"transform":671},[639,850,851],{"dataMmlNode":674},[664,852],{"dataC":677,"xLinkHref":853},"#MJX-2-TEX-I-1D465",[639,855,856],{"dataMmlNode":681,"transform":682},[664,857],{"dataC":685,"xLinkHref":858},"#MJX-2-TEX-N-31",[639,860,861],{"dataMmlNode":662,"transform":689},[664,862],{"dataC":692,"xLinkHref":863},"#MJX-2-TEX-N-2212",[639,865,866,870],{"dataMmlNode":670,"transform":696},[639,867,868],{"dataMmlNode":674},[664,869],{"dataC":677,"xLinkHref":853},[639,871,872],{"dataMmlNode":681,"transform":682},[664,873],{"dataC":705,"xLinkHref":874},"#MJX-2-TEX-N-32",[639,876,877],{"dataMmlNode":662,"transform":709},[664,878],{"dataC":712,"xLinkHref":879},"#MJX-2-TEX-N-29",[639,881,882],{"dataMmlNode":681,"transform":716},[664,883],{"dataC":705,"xLinkHref":874},[639,885,887],{"dataMmlNode":662,"transform":886},"translate(4454.1,0)",[664,888],{"dataC":724,"xLinkHref":889},"#MJX-2-TEX-N-2B",[639,891,893],{"dataMmlNode":662,"transform":892},"translate(5232.1,0)",[664,894],{"dataC":895,"xLinkHref":896},"2E","#MJX-2-TEX-N-2E",[639,898,900],{"dataMmlNode":662,"transform":899},"translate(5676.8,0)",[664,901],{"dataC":895,"xLinkHref":896},[639,903,905],{"dataMmlNode":662,"transform":904},"translate(6121.4,0)",[664,906],{"dataC":895,"xLinkHref":896},[639,908,910],{"dataMmlNode":662,"transform":909},"translate(6566.1,0)",[664,911],{"dataC":724,"xLinkHref":889},[639,913,915,955],{"dataMmlNode":655,"transform":914},"translate(7344.1,0)",[639,916,917,921,934,939,950],{"dataMmlNode":658,"dataMjxTexclass":659},[639,918,919],{"dataMmlNode":662},[664,920],{"dataC":666,"xLinkHref":846},[639,922,923,929],{"dataMmlNode":670,"transform":671},[639,924,925],{"dataMmlNode":674},[664,926],{"dataC":927,"xLinkHref":928},"1D45B","#MJX-2-TEX-I-1D45B",[639,930,932],{"dataMmlNode":681,"transform":931},"translate(633,-150) scale(0.707)",[664,933],{"dataC":685,"xLinkHref":858},[639,935,937],{"dataMmlNode":662,"transform":936},"translate(1647.8,0)",[664,938],{"dataC":692,"xLinkHref":863},[639,940,942,946],{"dataMmlNode":670,"transform":941},"translate(2648,0)",[639,943,944],{"dataMmlNode":674},[664,945],{"dataC":927,"xLinkHref":928},[639,947,948],{"dataMmlNode":681,"transform":931},[664,949],{"dataC":705,"xLinkHref":874},[639,951,953],{"dataMmlNode":662,"transform":952},"translate(3684.6,0)",[664,954],{"dataC":712,"xLinkHref":879},[639,956,958],{"dataMmlNode":681,"transform":957},"translate(4106.6,477.1) scale(0.707)",[664,959],{"dataC":705,"xLinkHref":874},[639,961,962],{"dataMmlNode":662,"transform":776},[664,963],{"dataC":779,"xLinkHref":964},"#MJX-2-TEX-LO-221A",[782,966],{"width":967,"height":785,"x":786,"y":787},11854.2,"\nФормула расстояния универсальна: даже если вы используете набор из миллиона чисел, расстояние вычисляется по той же формуле.\nЕстественно спросить: какой смысл передает метрика расстояния с пятью числами?\nОна сообщает, насколько близки между собой эти наборы из пяти чисел.",[551,970,971],{},[554,972,973],{},"Массивы чисел, такие как(2, 2) или (3, 4, 4, 1, 4) называются векторами.\nЕсли вам встретится статья о машинном обучении и вы увидите, что авторы говорят о векторах, знайте, что они имеют в виду подобный массив чисел.",[554,975,976],{},"Теперь порекомендовать фильм Алексею будет несложно: если Сергею понравился какой-то фильм, мы рекомендуем его Алексею, и наоборот.\nВы только что построили систему, рекомендующую фильмы.",[554,978,979],{},"Если вы являетесь пользователем приложения с фильмами, то оно постоянно напоминает вам:\n«Пожалуйста, оценивайте больше фильмов. Чем больше фильмов вы оцените, тем точнее будут наши рекомендации».\nТеперь вы знаете почему: чем больше фильмов вы оцениваете, тем точнее рекомендательная система определяет, с какими пользователями у вас общие вкусы.",[566,981],{"id":982},"",[984,985],"card-collapsible-num-answers",{":isAnswers":986,":isList":987,":startOl":988,"isText":989,"title":990},"[\"Можно воспользоваться нормализацией: вы вычисляете среднюю оценку для каждого человека и используете ее для масштабирования оценок. Например, вы определили, что средняя оценка первого равна 3, а средняя оценка второго — 3,5. Соответственно оценки первого немного увеличиваются так, чтобы ее средняя оценка тоже была равна 3,5. После этого оценки можно сравнивать по единой шкале.\",\"При применении алгоритма k ближайших соседей можно увеличить вес оценок авторитетов. Предположим, у вас трое соседей: Антон, Олег и Сергей(авторитет). Они поставили фильму оценки 3, 4 и 5 соответственно. Вместо того чтобы вычислять среднее арифметическое их оценок (3 + 4 + 5 \u002F 3 = 4 звезды), вы просто повышаете вес оценки авторитета Сергея: 3 + 4 + 5 + 5 + 5 \u002F 5 = 4,4 звезды.\"]","[\"В примере с приложением просмотра фильмов сходство между двумя пользователями оценивалось по формуле расстояния. Но не все пользователи оценивают фильмы одинаково. Допустим, есть два пользователя, вкусы которых совпадают. Но первый ставит 5 баллов любому фильму, который ему понравился, а второй более разборчив и ставит пятерки только самым лучшим фильмам. Вроде бы вкусы одинаковые, но по метрике расстояния они не являются соседями. Как учесть различия в стратегиях выставления оценок?\",\"Предположим, рекомендательная система определяет группу «авторитетов». Скажем, Иван и Сергей относятся к числу авторитетов приложения просмотра фильмов, поэтому их оценки оказывают более сильное влияние, чем оценки рядовых пользователей. Как изменить систему рекомендаций, чтобы она учитывала повышенную ценность оценок авторитетов?\"]","1","Попробуйте ответить на следующие вопросы","УПРАЖНЕНИЯ",[566,992,994],{"id":993},"регрессия","Регрессия",[554,996,997],{},"А теперь предположим, что просто порекомендовать фильм недостаточно: вы хотите спрогнозировать, какую оценку Алексей поставит фильму.\nВозьмите 5 пользователей, находящихся вблизи от нее.\nВ числе «5» нет ничего особенного: с таким же успехом можно взять 2 ближайших пользователей, 10 или 10 000.\nПоэтому-то алгоритм и называется «алгоритмом k ближайших пользователей», а не «алгоритмом 5 ближайших пользователей»!\nДопустим, вы пытаетесь угадать оценку Алексея для фильма «». Как этот фильм оценили Иван, Сергей, Лариса, Ольга и Антон?",[999,1000,1001,1014],"table",{},[1002,1003,1004],"thead",{},[1005,1006,1007,1011],"tr",{},[1008,1009,1010],"th",{},"Имя",[1008,1012,1013],{},"Оценка",[1015,1016,1017,1026,1034,1041,1048],"tbody",{},[1005,1018,1019,1023],{},[1020,1021,1022],"td",{},"Сергей",[1020,1024,1025],{},"4",[1005,1027,1028,1031],{},[1020,1029,1030],{},"Иван",[1020,1032,1033],{},"5",[1005,1035,1036,1039],{},[1020,1037,1038],{},"Лариса",[1020,1040,1025],{},[1005,1042,1043,1046],{},[1020,1044,1045],{},"Ольга",[1020,1047,1033],{},[1005,1049,1050,1053],{},[1020,1051,1052],{},"Антон",[1020,1054,1055],{},"3",[554,1057,1058],{},"Если вычислить среднее арифметическое их оценок, вы получите 4,2. Такой метод прогнозирования называется регрессией.\nУ алгоритма k ближайших соседей есть два основных применения — классификация и регрессия:",[1060,1061,1062,1066],"ul",{},[1063,1064,1065],"li",{},"классификация = распределение по категориям;",[1063,1067,1068],{},"регрессия = прогнозирование ответа (в числовом выражении).",[554,1070,1071],{},"Регрессия чрезвычайно полезна. Представьте, что вы открыли маленькую булочную и каждый день выпекаете свежий хлеб.\nВы пытаетесь предсказать, сколько буханок следует испечь на сегодня. Есть несколько признаков:",[1060,1073,1074,1077,1080],{},[1063,1075,1076],{},"погода по шкале от 1 до 5 (1 = плохая, 5 = отличная);",[1063,1078,1079],{},"праздник или выходной (1, если сегодня праздник или выходной, 0 в противном случае);",[1063,1081,1082],{},"проходят ли сегодня спортивные игры (1 = да, 0 = нет).",[554,1084,1085],{},"И вы знаете, сколько буханок хлеба было продано в прошлом при разных сочетаниях признаков.\nA(5,1,0) = 300 буханок; B(3,1,1) = 225; C(1,1,0) = 75; D(4,0,1) = 200; E(4,0,0) = 150; F(2,0,0) = 50.",[554,1087,1088],{},"Сегодня выходной и хорошая погода. Сколько буханок вы продадите на основании только что приведенных данных?\nИспользуем алгоритм k ближайших соседей для k = 4. Сначала определим четырех ближайших соседей для этой точки: (4,1,0) = ?.\nНиже перечислены расстояния. Точки A, B, D и E являются ближайшими: A - 1, B - 2, C - 9, D - 2, E - 1, F - 5.\nВычисляя среднее арифметическое продаж в эти дни, вы получаете ≈ 218.\nЗначит, именно столько буханок нужно выпекать на сегодня!",[551,1090,1091],{},[554,1092,1093,1094],{},"Выше мы использовали формулу расстояния для вычисления степени сходства.\nНо является ли эта формула лучшей?\nНа практике также часто применяется метрика близости косинусов.\nМетрика близости косинусов не измеряет расстояния между двумя векторами.\nВместо этого она сравнивает углы двух векторов и в целом лучше подходит для подобных случаев.\n",[1095,1096,1097],"em",{},"Тема метрики близости косинусов выходит за рамки этой статьи, вам стоит самостоятельно поискать информацию, если вы будете применять алгоритм k ближайших соседей!",[574,1099,1101],{"id":1100},"выбор-признаков","Выбор признаков",[554,1103,1104],{},"Чтобы подобрать рекомендации, вы предлагаете пользователям ставить оценки категориям фильмов.\nА если бы вы вместо этого предлагали им ставить оценки картинкам?\nНаверное, вам удалось бы найти пользователей, которые ставили похожие оценки этим картинкам.\nОднако у вас получилась бы самая плохая рекомендательная система в мире, потому что эти «признаки» не имеют никакого отношения к их вкусам в области кино!\nИли представьте, что вы предлагаете пользователям оценить фильмы для формирования рекомендаций — но только «Игру престолов», «Игру\nпрестолов-2» и «Игру престолов-3». Эти оценки ничего не скажут вам о вкусах пользователей.\nКогда вы работаете с алгоритмом k ближайших соседей, очень важно правильно выбрать признаки для сравнения.\nПод правильным выбором признаков следует понимать:",[1060,1106,1107,1110],{},[1063,1108,1109],{},"признаки, напрямую связанные с фильмами, которые вы пытаетесь рекомендовать;",[1063,1111,1112],{},"признаки, не содержащие смещения (например, если предлагать пользователям оценивать только комедии, вы не получите никакой информации об их отношении к боевикам).",[554,1114,1115],{},"Как вы думаете, оценки хорошо подходят для рекомендации фильмов? Возможно, я поставил «Золушке» более высокую оценку, чем «Охотникам за\nприведениями», но на самом деле я провел больше времени за просмотром «Охотников».\nКак улучшить рекомендательную систему?\nВозвращаясь к примеру с пекарней: сможете ли вы придумать два хороших и два плохих признака, которые можно было бы выбрать для прогнозирования объема выпечки?\nВозможно, нужно выпечь побольше хлеба после рекламы в газете. Или увеличить объем производства по понедельникам.\nВ том, что касается выбора хороших признаков, не существует единственно правильного ответа.\nТщательно продумайте все факторы, которые необходимо учесть при прогнозировании.",[566,1117],{"id":1118},"_1",[984,1120],{":isAnswers":1121,":isList":1122,":startOl":1055,"isText":989,"title":1123},"[\"Слишком мало. Если ограничиться малым числом соседей, существует высокая вероятность того, что результаты будут искажены. Существует хорошее эмпирическое правило: для N пользователей следует рассматривать корень из N соседей.\"]","[\"У сервиса просмотра фильмов миллионы пользователей. В приведенном ранее примере рекомендательная система строилась для пяти ближайших соседей. Пять — это слишком мало? Слишком много?\"]","УПРАЖНЕНИЕ",[1125,1126,1128],"h3",{"id":1127},"знакомство-с-машинным-обучением","Знакомство с машинным обучением",[554,1130,1131],{},"Мало того, что алгоритм k ближайших соседей полезен — он открывает путь в волшебный мир машинного обучения!\nСуть машинного обучения — сделать ваш компьютер более разумным.\nВы уже видели один пример машинного обучения: построение рекомендательной системы.\nРассмотрим другие примеры.",[566,1133,1135],{"id":1134},"ocr","OCR",[554,1137,1138],{},"Сокращение OCR означает «Optical Character Recognition», то есть «оптическое распознавание текста».\nИначе говоря, вы берете фотографию страницы текста, а компьютер автоматически преобразует изображение в текст.\nGoogle использует OCR для оцифровки книг. Как работает OCR?\nДля примера возьмем следующую цифру: 7.",[554,1140,1141],{},"Как автоматически определить, что это за цифра? Можно воспользоваться алгоритмом k ближайших соседей:",[1143,1144,1145,1148],"ol",{},[1063,1146,1147],{},"Переберите изображения цифр и извлеките признаки.",[1063,1149,1150],{},"Получив новое изображение, извлеките признаки и проверьте ближайших соседей.",[554,1152,1153],{},"По сути, это та же задача, что и задача классификации.\nВ общем случае алгоритмы OCR основаны на выделении линий, точек и кривых.\nЗатем при получении нового символа из него можно извлечь те же признаки.\nИзвлечение признаков в OCR происходит сложнее чем в задачах классификации.\nОднако важно понимать, что даже сложные технологии строятся на основе простых идей(таких, как алгоритм k ближайших соседей).\nТе же принципы могут использоваться для распознавания речи или лиц.\nКогда вы отправляете фотографию на Яндекс Диск, иногда сервису Яндекса хватает сообразительности для автоматической пометки людей на фото.\nДа это машинное обучение в действии!\nПервый шаг OCR, в ходе которого перебираются изображения цифр и происходит извлечение признаков, называется тренировкой.\nВ большинстве алгоритмов машинного обучения присутствует фаза тренировки: прежде чем компьютер сможет решить свою задачу, его необходимо натренировать.\nВ следующем примере рассмотрим создание спам-фильтров, и в нем тоже есть шаг тренировки.",[566,1155,1157],{"id":1156},"построение-спам-фильтра","Построение спам-фильтра",[554,1159,1160],{},"Спам-фильтры используют другой простой алгоритм, называемый наивным классификатором Байеса.\nСначала наивный классификатор Байеса тренируется на данных.\nПредположим, вы получили сообщение с темой «Получите свой миллион прямо сейчас!» Это спам?\nПредложение можно разбить на слова, а затем для каждого слова проверить вероятность присутствия этого слова в спам сообщении.\nНапример, в нашей очень простой модели слово «миллион» встречается только в спаме.\nНаивный классификатор Байеса вычисляет вероятность того, что сообщение с большой вероятностью является спамом.\nНа практике он применяется примерно для тех же целей, что и алгоритм k ближайших соседей.\nНапример, наивный классификатор Байеса может использоваться для классификации фруктов: есть большой и красный фрукт.\nКакова вероятность того, что он окажется грейпфрутом?\nЭто простой, но весьма эффективный алгоритм — из тех, что нравятся больше всего!",[566,1162,1164],{"id":1163},"прогнозы-на-биржевых-торгах","Прогнозы на биржевых торгах",[554,1166,1167],{},"Есть одна задача, в которой трудно добиться успеха машинным обучением: точно спрогнозировать курсы акций на бирже.\nКак выбрать хорошие признаки? Предположим, вы говорите, что если курс акций рос вчера, то он будет расти и сегодня.\nХороший это признак или нет? Или, предположим, вы утверждаете, что курс всегда снижается в апреле. Сработает или нет?\nНе существует гарантированного способа прогнозировать будущее на основании прошлых данных.\nПрогнозирование будущего — сложное дело, а при таком количестве переменных оно становится почти невозможным.",[1125,1169,1171],{"id":1170},"тренировка-модели-машинного-обучения","Тренировка модели машинного обучения",[554,1173,1174],{},"Тренировка нейросети МО состоит из нескольких основных этапов:",[1143,1176,1177,1180,1183,1185,1188,1191],{},[1063,1178,1179],{},"Сбор данных",[1063,1181,1182],{},"Анализ и очистка данных",[1063,1184,577],{},[1063,1186,1187],{},"Процесс обучения на тестовых данных",[1063,1189,1190],{},"Проверка на новых данных",[1063,1192,1193],{},"Проверка(валидация) и корректировка модели",[554,1195,1196],{},"Рассмотрим последовательность действий по тренировке модели МО. Все начинается со сбора данных.\nВ примере с рекомендательной системой по фильмам данными были оценки пользователей.\nЗатем необходимо провести очистку данных, то есть удаление неподходящих данных.\nНапример, какой-нибудь пользователь не пожелал оценивать фильмы, поэтому расставил случайные оценки и перешел к следующему экрану.\nТакие данные необходимо удалить из набора. После этого требуется извлечь из данных признаки.\nПолучив признаки, можно переходить к тренировке модели.\nВыберите модель — например, k ближайших соседей, создайте структуру нейронов и саму нейросеть — и проведите ее тренировку на 90% данных.\nОставьте около 10% данных для проверки модели.\nПосле того как модель пройдет обучение, протестируйте ее, предложив ей составить прогноз.\nЧтобы оценить качество прогноза, используйте зарезервированные или новые данные.\nНапример, вы хотите проверить рекомендательную модель фильмов.\nМожно спросить, понравились ли некоторому пользователю некоторые фильмы и сериалы. Модель выдаёт прогнозы.\nА мы при этом заранее знаем, какие фильмы нравятся пользователю, — эта информация содержится в 10 % данных, которые мы зарезервировали.\nЭти зарезервированные данные сравниваются с прогнозами модели.\nПосле сравнения результатов модели и реальных данных, можно сделать вывод о том, что модель выдала хороший результат или не очень.\nХороший результат у модели получается тогда, когда числа достаточно близки к реальным оценкам пользователя.\nЭтот шаг тестирования модели называется проверкой (или валидацией) модели.\nПосле проверки можно вернуться к модели и скорректировать ее.\nПредставьте, что вы построили модель k ближайших соседей, в которой k = 5.\nМожно опробовать ее с k = 7, чтобы посмотреть, не даст ли она лучший результат. Это называется корректировкой(или подкруткой) параметров.\nПосле того как вы завершите тренировку и оценку модели, ваша модель будет готова к работе.\nТак выглядит процедура построения модели МО в общем случае.",[554,1198,1199],{},[1095,1200,1201],{},"Надеюсь, вы хотя бы в общих чертах поняли, что можно сделать с помощью алгоритма k ближайших соседей и машинного обучения!\nМашинное обучение — интересная область, и при желании в нее можно зайти достаточно глубоко.",[566,1203],{"id":1204},"_2",[546,1206],{":isList":1207,"title":1208},"[\"Алгоритм k ближайших соседей применяется для классификации и регрессии. В нем используется проверка k ближайших соседей.;\",\"Классификация = распределение по категориям;\",\"Регрессия = прогнозирование результата (например, в виде числа);\",\"«Извлечением признаков» называется преобразование элемента (например, пользователя) в список чисел, которые могут использоваться для сравнения;\",\"Качественный выбор признаков — важная часть успешного алгоритма k ближайших соседей;\"]","ШПАРГАЛКА",[1125,1210,1212],{"id":1211},"ещё-об-алгоритмах","Ещё об алгоритмах",[554,1214,1215],{},"Ниже краткий обзор 10 алгоритмов, которые не рассматривались. Вы узнаете, для чего нужны эти алгоритмы.\nА также рекомендация книг, которые стоит читать дальше в зависимости от того, какие темы вам интересны.",[566,1217,1219],{"id":1218},"линейная-регрессия","Линейная регрессия",[554,1221,1222],{},"Представьте, что вы хотите продать свой дом.\nЕго площадь составляет 300 квадратных метров.\nВы изучаете описания домов, недавно проданных по соседству:",[1143,1224,1225,1228,1231],{},[1063,1226,1227],{},"100 кв. метров 10 миллионов рублей;",[1063,1229,1230],{},"200 кв. метров 13 миллионов рублей;",[1063,1232,1233],{},"400 кв. метров 25 миллионов рублей.",[554,1235,1236],{},"Какую цену вы бы назначили за свой дом, исходя из этой информации?\nНиже представлено одно из возможных решений. Сначала вы наносите все точки на график.\nЗатем соединяете их прямой линией(отсюда и название линейная).",[554,1238,1239],{},[594,1240],{"alt":1241,"src":1242},"Пример линейной регрессии","\u002Fimages\u002Fblog\u002Fpython\u002Fst35\u002Fimg_1.png",[554,1244,1245],{},"Теперь вы видите, где на этой линии находится точка 300 квадратных метров.\nСоответствующую ей цену можно сделать начальной ценой.\nТак работает линейная регрессия. Она выстраивает линию из заданной группы точек, а затем использует эту линию для вычисления прогнозов.\nЛинейная регрессия уже давно применяется в статистике, а теперь и в машинном обучении, поскольку это метод, с которого легко начинать.\nЛинейная регрессия полезна, если значения непрерывны. Если вам нужно сделать прогноз, проще всего использовать именно линейную регрессию.",[566,1247,1249],{"id":1248},"инвертированные-индексы","Инвертированные индексы",[554,1251,1252],{},"Перед вами сильно упрощенное объяснение того, как работает поисковая система.\nДопустим, имеются три веб-страницы с простым содержимым.\nСтроиться хеш-таблица для этого содержимого или проще python словарь.\nКлючами словаря являются слова, а значения указывают, на каких страницах встречается каждое слово.\nТеперь предположим, что пользователь ищет слово \"python\".\nДалее проверяется, на каких страницах это слово встречается.\nПусть, слово встречается на страницах А и B. Выведем эти страницы в результатах поиска.\nИли предположим, что пользователь ищет слово \"питон\".\nИ система проверяет, что это слово встречается на страницах A и C.\nНесложно, верно?\nХеш-таблица — это очень полезная структура данных: хеш-таблица, связывающая слова с местами, в которых эти слова встречаются.\nТакая структура данных, называемая инвертированным индексом, часто используется для построения поисковых систем.\nЕсли вас интересует область поиска, эта тема станет хорошей отправной точкой для дальнейшего изучения.",[566,1254,1256],{"id":1255},"преобразование-фурье","Преобразование Фурье",[554,1258,1259,1260],{},"Преобразование Фурье — действительно выдающийся алгоритм: великолепный, элегантный и имеющий миллион практических применений.\nПример для преобразования Фурье: если у вас есть коктейль, преобразование Фурье сообщает, из каких ингредиентов он состоит.\nИли для заданной песни преобразование разделяет ее на отдельные частоты.\nОказывается, эта простая идея находит множество практических применений.\nНапример, если песню можно разложить на частоты, вы можете усилить тот диапазон, который вас интересует, — скажем, усилить низкие частоты и приглушить высокие.\nПреобразование Фурье прекрасно подходит для обработки сигналов.\nТакже оно может применяться для сжатия музыки: сначала звуковой файл разбивается на составляющие.\nПреобразование Фурье сообщает, какой вклад вносит каждая составляющая в музыку, что позволяет исключить несущественные составляющие.\nСобственно, именно так работает музыкальный формат MP3!\nМузыка — не единственный вид цифровых сигналов.\nГрафический формат JPG также использует сжатие и работает по тому же принципу.\nКроме того, преобразование Фурье применяется для прогнозирования землетрясений и анализа ДНК.\nС его помощью можно построить приложение, которое находит песни по отрывкам.\nПреобразование Фурье очень часто применяется на практике!\n",[558,1261,1265],{"href":1262,"rel":1263},"https:\u002F\u002Fproglib.io\u002Fp\u002Fpreobrazovaniya-fure-dlya-obrabotki-signalov-s-pomoshchyu-python-2020-11-03",[1264],"nofollow","Подробнее о преобразовании Фурье в работе со звуком есть отличная статья.",[566,1267,1269],{"id":1268},"параллельные-алгоритмы","Параллельные алгоритмы",[554,1271,1272,1273,1276,1277,1280,1281,1283,1284,1287],{},"Следующие три темы связаны с масштабируемостью и обработкой больших объемов данных.\nКогда-то компьютеры становились все быстрее и быстрее.\nЕсли вы хотели, чтобы ваш алгоритм работал быстрее, можно было подождать несколько месяцев и запустить программу на более мощном компьютере.\nНо сейчас этот период подошел к концу.\nСовременные компьютеры и ноутбуки оснащаются многоядерными процессорами. Чтобы алгоритм заработал быстрее,\nнеобходимо преобразовать его в форму, подходящую для параллельного выполнения сразу на всех ядрах!\nРассмотрим простой пример. Лучшее время выполнения для алгоритма сортировки равно приблизительно ",[1095,1274,1275],{},"O(n log n)",".\nИзвестно, что массив невозможно отсортировать за время ",[1095,1278,1279],{},"O(n)",", если только не воспользоваться параллельным алгоритмом!\nСуществует параллельная версия быстрой сортировки, которая сортирует массив за время ",[1095,1282,1279],{},".\nПараллельный алгоритм трудно разработать.\nИ так же трудно убедиться в том, что он работает правильно, и понять, какой прирост скорости он обеспечивает.\nОдно можно заявить твердо: ",[1095,1285,1286],{},"выигрыш по времени нелинеен",".\nСледовательно, если процессор вашего компьютера имеет два ядра вместо одного, из этого не следует, что ваш алгоритм по волшебству заработает вдвое быстрее.\nЭто объясняется несколькими причинами:",[1060,1289,1290,1296,1302],{},[1063,1291,1292,1295],{},[1095,1293,1294],{},"Затраты ресурсов на управление параллелизмом"," — допустим, нужно отсортировать массив из 1000 элементов. Как разбить эту задачу для выполнения на двух ядрах? Выделить каждому ядру 500 элементов, а затем объединить два отсортированных массива в один большой отсортированный массив? Слияние двух массивов требует времени.",[1063,1297,1298,1301],{},[1095,1299,1300],{},"Закон Амдала"," — представьте, что вы пишете картину. Это занимает очень много времени, допустим около 30 часов. В идеале вам хотелось бы уложиться в 10 часов. Вы решаете оптимизировать процесс. Для этого разбиваете его на два шага: (1) эскиз и (2) рисование красками. Исходный эскиз не обязательно рисовать вручную — конечно, с помощью трейсинга(обводки) это делается быстрее. Но при следующей попытке на картину уходит 29 часов и 5 минут! Что произошло? Раньше эскиз занимал 1 час. Вы сократили его до 5 минут, что стало значительным улучшением. Тем не менее бóльшая часть времени приходится на рисование красками, так что оптимизация оказалась незначительной. Это проявление так называемого закона Амдала. Он гласит, что при оптимизации одной части системы выигрыш в производительности ограничивается тем, какую долю времени занимает эта часть. В данном случае время создания эскиза сокращается до 1\u002F12 исходного значения. При этом экономятся 55 минут. Если бы нам удалось сократить время рисования красками в той же степени, это сэкономило бы 2090 минут!Ускоряя алгоритм за счет параллелизации, подумайте, какую его часть следует распараллелить — создание эскиза или рисование?",[1063,1303,1304,1307],{},[1095,1305,1306],{},"Распределение нагрузки"," — допустим, необходимо выполнить 10 задач, и вы назначаете каждому ядру 5 задач. Однако ядру A достаются все простые задачи, поэтому оно выполняет свою работу за 10 секунд, тогда как ядро B справится со сложными задачами только за минуту. Это означает, что ядро A целых 50 секунд простаивает, пока ядро B выполняет всю работу! Как организовать равномерное распределение работы, чтобы оба ядра трудились с одинаковой интенсивностью?",[554,1309,1310],{},"Если вас интересует теоретическая сторона производительности и масштабируемости, возможно, параллельные алгоритмы — именно то, что вам нужно!",[574,1312,1314],{"id":1313},"mapreduce","MapReduce",[554,1316,1317],{},"Существует разновидность параллельных алгоритмов, которая в последнее время активно набирает популярность: распределенные алгоритмы.\nКонечно, параллельный алгоритм удобно запускать на компьютере, если для его выполнения требуется от двух до четырех ядер. Но если нужны сотни?\nТогда алгоритм записывают так, чтобы он мог выполняться на множестве машин.\nКомпания Google популяризировала распределенный алгоритм, который называется MapReduce, но его функции известны уже давно.\nДля чего нужны распределенные алгоритмы?\nПредположим, имеется таблица с миллиардами или триллионами записей и к ней нужно сделать сложный запрос SQL.\nВ MySQL это сделать не удастся, потому что MySQL начнет «тормозить» уже после нескольких миллиардов записей.\nИспользуйте MapReduce!\nИли, предположим, вам нужно обработать длинный список задач.\nОбработка каждой задачи занимает 10 секунд, а всего в списке 1 миллион задач.\nЕсли выполнять эту работу на одном компьютере, она займет несколько месяцев!\nЕсли бы ее можно было выполнить на 100 машинах, работа завершилась бы за несколько дней.\nРаспределенные алгоритмы хорошо работают в ситуациях, когда нужно выполнить большой объем работы за максимально короткое время.",[566,1319,1321],{"id":1320},"фильтры-блума-и-hyperloglog","Фильтры Блума и HyperLogLog",[554,1323,1324,1325,1328],{},"Представьте себя на месте сайта Reddit. Когда пользователь публикует ссылку, нужно проверить, публиковалась ли эта ссылка ранее.\nИстории, которые еще не публиковались, считаются более ценными.\nИли представьте себя на месте поискового бота Google.\nОбрабатывать веб-страницу нужно только в том случае, если она еще не обрабатывалась ранее.\nИтак, нужно проверить, обрабатывалась ли страница ранее.\nИли представьте себя на месте bit.ly — сервиса сокращения URL.\nПользователи не должны перенаправляться на вредоносные сайты.\nУ вас имеется набор URL-адресов, которые считаются вредоносными.\nТеперь нужно выяснить, не направляется ли пользователь на URL-адрес из этого набора.\nВо всех этих примерах возникает одна проблема.\nИмеется очень большой набор данных.\nПоявляется новый объект, и вы хотите узнать, содержится ли он в существующем наборе.\nЭта задача быстро решается при помощи хеша.\nНапример, представьте, что Google создает большой хеш, ключами которого являются все обработанные страницы.\nКак узнать, обрабатывался ли сайт ashtana.ru? Нужно заглянуть в хеш.\nУ ashtana.ru имеется свой ключ в хеше, а значит, адрес уже обрабатывался.\nСреднее время обращения к элементам в хеш-таблице составляет ",[1095,1326,1327],{},"O(1)",".\nТаким образом, вы узнали о том, что страница ashtana.ru уже проиндексирована за постоянное время. Неплохо!\nВот только этот хеш получится просто огромным.\nGoogle индексирует триллион веб-страниц. Если хеш содержит все URL-адреса, индексируемые Google, он займет слишком много места.\nУ Reddit и bit.ly возникает аналогичная проблема. Сталкиваясь с такими объемами данных, приходится действовать более изобретательно!",[574,1330,1332],{"id":1331},"фильтры-блума","Фильтры Блума",[554,1334,1335],{},"Для решения проблемы можно воспользоваться вероятностными структурами данных, которые называются фильтрами Блума.\nОни дают ответ, который может оказаться ложным, но с большой вероятностью является правильным.\nВместо того чтобы обращаться к хешу, вы спрашиваете у фильтра Блума, обрабатывался ли этот URL-адрес ранее.\nХеш-таблица даст точный ответ. Фильтр Блума дает ответ, правильный с высокой вероятностью:",[1060,1337,1338,1341],{},[1063,1339,1340],{},"возможны ложноположительные срабатывания. Фильтр скажет: «Этот сайт уже обрабатывался», хотя этого не было;",[1063,1342,1343],{},"ложноотрицательные срабатывания исключены. Если фильтр утверждает, что сайт не обрабатывался, вы можете быть в этом уверены.",[554,1345,1346],{},"Фильтры Блума хороши тем, что занимают очень мало места.\nХеш-таблице пришлось бы хранить все URL-адреса, обрабатываемые Google, а фильтру Блума это не нужно.\nФильтр Блума очень удобен тогда, когда нет необходимости в точном ответе(как во всех приведенных примерах).",[574,1348,1350],{"id":1349},"hyperloglog","HyperLogLog",[554,1352,1353],{},"Примерно так же действует другой алгоритм, который называется HyperLogLog.\nПредположим, Google хочет подсчитать количество уникальных поисков, выполненных пользователями.\nИли Amazon хочет подсчитать количество уникальных предметов, просмотренных пользователями за сегодняшний день.\nДля получения ответов на эти вопросы потребуется очень много места!\nТак, в примере с Google придется вести журнал всех уникальных вариантов поиска.\nКогда пользователь что-то ищет, вы сначала проверяете, присутствует ли условие в журнале, и если нет, добавляете его.\nДаже для одного дня этот журнал получится гигантским.\nHyperLogLog аппроксимирует количество уникальных элементов в множестве.\nКак и фильтры Блума, он не дает точного ответа, но выдает достаточно близкий результат с использованием малой части памяти, которую обычно занимает такая задача.\nЕсли вы используете большие объемы данных и вас устраивают приближенные ответы — воспользуйтесь вероятностными алгоритмами!",[566,1355,1357],{"id":1356},"https-и-обмен-ключами-диффи-хеллмана","HTTPS и обмен ключами Диффи — Хеллмана",[554,1359,1360],{},"HTTPS — опора современного интернета.\nЭтот протокол обеспечивает безопасные онлайн-транзакции, от ввода пароля до оплаты покупок.\nРабота HTTPS основана на шифровании сообщений между клиентом и сервером.\nКак же работает шифрование? Функции передаются сообщение и секретный ключ.\nЗатем функция генерирует зашифрованное сообщение.\nЧтобы расшифровать его, передайте зашифрованное сообщение и тот же ключ функции, и вы получите исходное сообщение.\nКогда вы отправляете данные серверу, ваш браузер зашифровывает сообщение, после чего сервер расшифровывает его.\nДа, кроме одного: как проверить, что браузер и сервер используют один и тот же ключ?\nПомните, что для работы HTTPS обе стороны должны иметь одинаковые ключи.\nНо как задать ключ, чтобы никто его не видел? Если отправить ключ серверу, злоумышленник сможет перехватить этот ключ.\nКак задать ключ, чтобы только браузер и сервер знали его? Задача кажется неразрешимой, но это не так!\nДля ее решения существует очень умный алгоритм, называемый обменом ключей Диффи — Хеллмана.",[554,1362,1363],{},"Ниже описано, как работает алгоритм Диффи — Хеллмана.\nНа шаге 1 мы генерируем собственные ключи. Я — клиент, и я генерирую ключ для себя. Сервис также генерирует ключ.\nЭти ключи разные. Мы не знаем ключи друг друга, они закрытые. В реальности ключи представляют собой байты.\nНа шаге 2 генерируется общий шаблон. Это открытый шаблон. Он виден обеим сторонам и всем остальным. Нам неважно, кто его видит.\nНа шаге 3 этот шаблон совмещается с закрытыми ключами.\nВ результате мы получаем открытые ключи. Раз они открытые, нас не интересует, кто их видит.\nСервер видит мой открытый ключ, а я вижу его открытый ключ.\nНаконец, на шаге 4 я получаю открытый ключ сервера и совмещаю его со своим закрытым ключом.\nСервис делает то же самое с моим открытым ключом.\nТеперь у нас одинаковые ключи! У каждого из нас есть ключ, объединяющий три шаблона.\nНам удалось задать ключ, не отправляя ключи друг другу.\nЗаданный ключ называется общим секретом; так работает обмен ключами Диффи — Хеллмана.",[554,1365,1366],{},"HTTPS — интересная и важная часть нашей повседневной жизни. Вот немного терминологии, связанной с HTTPS:",[1060,1368,1369,1372,1375],{},[1063,1370,1371],{},"TLS — протокол безопасности транспортного уровня (Transport Layer Security). TLS используется для установления безопасного соединения.",[1063,1373,1374],{},"SSL — прежнее название TLS, но люди часто не различают их. Если вы слышите, как кто-то упоминает SSL, то, скорее всего, речь идет о TLS. В этом протоколе часто находят дефекты безопасности, поэтому его постоянно приходится обновлять. Протокол TLS впервые появился в 1999 году. Все версии протокола SSL, выпущенные до TLS, небезопасны.",[1063,1376,1377],{},"Шифрование с симметричным ключом — в нашем примере выше обе стороны используют одинаковые ключи. Но существует и асимметричное шифрование с открытым ключом, когда обе стороны используют разные ключи. Я говорю о шифровании с симметричным ключом, потому что оно используется HTTPS.",[554,1379,1380],{},"HTTPS использует измененную версию обмена ключей Диффи — Хеллмана, называемую эфемерным обменом ключей Диффи — Хеллмана.\nОна работает так же, как было показано, кроме того, что закрытые ключи генерируются заново для каждого соединения.\nЭто означает, что даже если злоумышленнику станет известен один из закрытых ключей, он сможет расшифровать сообщения только одного соединения.\nКриптография — интересная и глубокая тема, в которую можно сильно погрузиться.",[566,1382,1384],{"id":1383},"локально-чувствительное-хеширование","Локально-чувствительное хеширование",[554,1386,1387,1388,1391,1392,1394,1395,1397],{},"Многие хеш-функции имеют одну важную особенность: они являются локально-нечувствительными.\nПредположим, имеется строка, для которой генерируется хеш-код с помощью алгоритма SHA-256: dog → cd6357.\nЕсли изменить в строке всего один символ, а потом сгенерировать хеш заново, строка полностью изменяется!\nИ это хорошо, потому что сравнение хешей не позволит атакующему определить, насколько он близок к взлому пароля.\nИногда требуется обратный результат: локально-чувствительная функция хеширования.\nЗдесь на помощь приходит алгоритм ",[1095,1389,1390],{},"Simhash",".\nПри незначительном изменении строки ",[1095,1393,1390],{}," генерирует хеш-код, который почти не отличается от исходного.\nЭто позволяет сравнивать хеш-коды и определять, насколько похожи две строки, — весьма полезная возможность!\nПримеры использования ",[1095,1396,1390],{},":",[1060,1399,1400,1403,1406,1409],{},[1063,1401,1402],{},"Google использует Simhash для выявления дубликатов в процессе индексирования.",[1063,1404,1405],{},"Система проверки на антиплагиат может использовать Simhash для обнаружения плагиата(копирования рефератов из интернета).",[1063,1407,1408],{},"Книжное издательство позволяет пользователям загружать документы или книги, чтобы они стали доступны для других пользователей. Но издатель не хочет, чтобы пользователи размещали информацию, защищенную авторским правом! С помощью Simhash сайт может обнаружить, что отправленная информация похожа на изданную книгу, и при обнаружении сходства автоматически запретить ее размещение.",[1063,1410,1411],{},"Simhash используется для выявления сходства между фрагментами текста.",[566,1413,1415],{"id":1414},"минимальные-кучи-и-приоритетные-очереди","Минимальные кучи и приоритетные очереди",[554,1417,1418,1419,1421,1422,1425],{},"Минимальная куча — структура данных, построенная на базе деревьев. В таких кучах хранятся числа.\nМинимальные кучи позволяют быстро найти наименьший элемент кучи, потому что наименьшее значение всегда находится в корне.\nЭто самое важное свойство минимальной кучи, и наименьший элемент находится за время ",[1095,1420,1327],{},".\nИли же за время ",[1095,1423,1424],{},"O(log n)"," его можно удалить из кучи, заменив новым минимумом.\nБлагодаря кучам проводить сортировку очень легко — просто продолжая запрашивать минимальное значение.\nИ сохранять значения по порядку. В конце куча будет пустой, а у вас появится отсортированный список чисел!\nТакой алгоритм называется пирамидальной сортировкой, или сортировкой кучей.\nМаксимальные кучи (невозрастающие пирамиды) очень похожи на минимальные, но у них в корне хранится наибольшее значение.\nКучи отлично подходят для реализации приоритетных очередей.\nВспомните, что очереди относятся к категории FIFO (First In, First Out — «первым пришел, первым вышел»).\nС другой стороны, стек относится к структуре данных LIFO(Last In, First Out — «последним пришел, первым вышел»).\nПриоритетная очередь похожа на обычную очередь, не считая того, что при запросе элемента приоритетная очередь выдает элемент с наибольшим приоритетом.\nПриоритетная очередь отлично подходит для реализации списка задач.\nСначала вы сохраняете в списке задачи, а затем запрашиваете задачу для работы; приоритетная очередь выдает задачу с наибольшим приоритетом.\nПриоритетные очереди также используются для реализации эффективной версии алгоритма Дейкстры.",[566,1427,1429],{"id":1428},"линейное-программирование","Линейное программирование",[554,1431,1432],{},"Линейное программирование — одна из самых интересных областей, которые мне известны.\nЛинейное программирование используется для максимизации некоторой характеристики при заданных ограничениях.\nПредположим, ваша компания выпускает два продукта: рубашки и сумки.\nНа рубашку требуется 1 метр ткани и 5 пуговиц. На изготовление сумки необходимо 2 метра ткани и 2 пуговицы.\nУ вас есть 11 метров ткани и 20 пуговиц.\nРубашка приносит прибыль 200 рублей, а сумка — 300.\nСколько рубашек и сумок следует изготовить для получения максимальной прибыли?\nЗдесь мы пытаемся максимизировать прибыль, а ограничения определяют количество имеющихся материалов.\nДругой пример: вы политик, пытающийся получить максимальное количество голосов.\nПредположим, что исследования показали, что на каждый голос жителя Белгорода требуется примерно 1 час работы (маркетинг, исследования и т.д.), а на каждый голос жителя Курска — 1,5 часа.\nВам нужны голоса как минимум 500 жителей Белгорода и как минимум 300 жителей Курска.\nВ вашем распоряжении 50 дней. Кроме того, затраты на жителя Белгорода составляют 200 рублей, а на жителя Курска — 100.\nВаш бюджет составляет 1500000 рублей. Какое максимальное количество голосов вы сможете получить от жителей двух городов?\nНа этот раз вы стремитесь к максимуму голосов при ограничениях по времени и деньгам.\nВозможно, вы подумаете: «Есть много задач решающие вопросы оптимизации. Как они связаны с линейным программированием?»\nВсе алгоритмы, работающие с графами, могут быть реализованы средствами линейного программирования.\nЛинейное программирование — намного более общая область, а задачи с графами составляют ее подмножество.\nВ линейном программировании используется симплекс-метод. Этот алгоритм достаточно сложен, поэтому я не привожу его.\nЕсли вы заинтересуетесь различными задачами оптимизации, поищите информацию о линейном программировании!",[551,1434,1435],{},[554,1436,1437],{},"Надеюсь, этот краткий обзор показал, как много всего ещё можно узнать.\nЯ считаю, что лучший способ узнать что-то — найти тему, которая вас интересует, и постоянно изучать её!",[1439,1440,1441],"style",{},"\nmjx-container[jax=\"SVG\"] {\n  direction: ltr;\n}\n\nmjx-container[jax=\"SVG\"] > svg {\n  overflow: visible;\n  min-height: 1px;\n  min-width: 1px;\n}\n\nmjx-container[jax=\"SVG\"] > svg a {\n  fill: blue;\n  stroke: blue;\n}\n\nmjx-container[jax=\"SVG\"][display=\"true\"] {\n  display: block;\n  text-align: center;\n  margin: 1em 0;\n}\n\nmjx-container[jax=\"SVG\"][display=\"true\"][width=\"full\"] {\n  display: flex;\n}\n\nmjx-container[jax=\"SVG\"][justify=\"left\"] {\n  text-align: left;\n}\n\nmjx-container[jax=\"SVG\"][justify=\"right\"] {\n  text-align: right;\n}\n\ng[data-mml-node=\"merror\"] > g {\n  fill: red;\n  stroke: red;\n}\n\ng[data-mml-node=\"merror\"] > rect[data-background] {\n  fill: yellow;\n  stroke: none;\n}\n\ng[data-mml-node=\"mtable\"] > line[data-line], svg[data-table] > g > line[data-line] {\n  stroke-width: 70px;\n  fill: none;\n}\n\ng[data-mml-node=\"mtable\"] > rect[data-frame], svg[data-table] > g > rect[data-frame] {\n  stroke-width: 70px;\n  fill: none;\n}\n\ng[data-mml-node=\"mtable\"] > .mjx-dashed, svg[data-table] > g > .mjx-dashed {\n  stroke-dasharray: 140;\n}\n\ng[data-mml-node=\"mtable\"] > .mjx-dotted, svg[data-table] > g > .mjx-dotted {\n  stroke-linecap: round;\n  stroke-dasharray: 0,140;\n}\n\ng[data-mml-node=\"mtable\"] > g > svg {\n  overflow: visible;\n}\n\n[jax=\"SVG\"] mjx-tool {\n  display: inline-block;\n  position: relative;\n  width: 0;\n  height: 0;\n}\n\n[jax=\"SVG\"] mjx-tool > mjx-tip {\n  position: absolute;\n  top: 0;\n  left: 0;\n}\n\nmjx-tool > mjx-tip {\n  display: inline-block;\n  padding: .2em;\n  border: 1px solid #888;\n  font-size: 70%;\n  background-color: #F8F8F8;\n  color: black;\n  box-shadow: 2px 2px 5px #AAAAAA;\n}\n\ng[data-mml-node=\"maction\"][data-toggle] {\n  cursor: pointer;\n}\n\nmjx-status {\n  display: block;\n  position: fixed;\n  left: 1em;\n  bottom: 1em;\n  min-width: 25%;\n  padding: .2em .4em;\n  border: 1px solid #888;\n  font-size: 90%;\n  background-color: #F8F8F8;\n  color: black;\n}\n\nforeignObject[data-mjx-xml] {\n  font-family: initial;\n  line-height: normal;\n  overflow: visible;\n}\n\nmjx-container[jax=\"SVG\"] path[data-c], mjx-container[jax=\"SVG\"] use[data-c] {\n  stroke-width: 3;\n}\n",{"title":982,"searchDepth":1443,"depth":1444,"links":1445},2,5,[1446],{"id":544,"depth":1443,"text":302,"children":1447},[1448,1452,1453,1456,1457,1463,1466],{"id":568,"depth":1449,"text":569,"children":1450},4,[1451],{"id":576,"depth":1444,"text":577},{"id":982,"depth":1449,"text":982},{"id":993,"depth":1449,"text":994,"children":1454},[1455],{"id":1100,"depth":1444,"text":1101},{"id":1118,"depth":1449,"text":982},{"id":1127,"depth":1458,"text":1128,"children":1459},3,[1460,1461,1462],{"id":1134,"depth":1449,"text":1135},{"id":1156,"depth":1449,"text":1157},{"id":1163,"depth":1449,"text":1164},{"id":1170,"depth":1458,"text":1171,"children":1464},[1465],{"id":1204,"depth":1449,"text":982},{"id":1211,"depth":1458,"text":1212,"children":1467},[1468,1469,1470,1471,1474,1478,1479,1480,1481],{"id":1218,"depth":1449,"text":1219},{"id":1248,"depth":1449,"text":1249},{"id":1255,"depth":1449,"text":1256},{"id":1268,"depth":1449,"text":1269,"children":1472},[1473],{"id":1313,"depth":1444,"text":1314},{"id":1320,"depth":1449,"text":1321,"children":1475},[1476,1477],{"id":1331,"depth":1444,"text":1332},{"id":1349,"depth":1444,"text":1350},{"id":1356,"depth":1449,"text":1357},{"id":1383,"depth":1449,"text":1384},{"id":1414,"depth":1449,"text":1415},{"id":1428,"depth":1449,"text":1429},"2026-05-21","Сценарии использования и ограничениями алгоритма k ближайших соседей. Рекомендации по темам, которые стоит изучать дальше.","md","images\u002Fblog\u002Fpython\u002Fst35\u002Fimg.png",{},35,{"title":302,"description":1483},"XxXV74jrfia4THoFmW400WVVaOY2oEv_sinQl05bgbA",{"id":1491,"title":298,"author":1492,"body":1494,"date":4628,"description":4629,"extension":1484,"image":4630,"meta":4631,"minRead":4632,"navigation":513,"num":4633,"path":299,"seo":4634,"stem":300,"__hash__":4635},"blog\u002Fblog\u002Fpython\u002Fst34.md",{"name":516,"avatar":1493},{"src":536,"alt":537},{"type":539,"value":1495,"toc":4593},[1496,1499,1502,1511,1515,1520,1523,1562,1565,1569,1630,1633,1636,1639,1642,1645,1701,1704,1707,1710,1713,1768,1771,1825,1828,1882,1885,1888,1891,1945,1948,2002,2005,2060,2063,2066,2069,2123,2126,2181,2184,2239,2242,2246,2249,2253,2256,2310,2313,2381,2384,2450,2453,2520,2523,2527,2530,2534,2537,2541,2544,2655,2659,2662,2666,2669,2737,2740,2823,2826,2910,2914,2917,2999,3002,3005,3009,3012,3016,3019,3023,3026,3034,3037,3048,3052,3055,3059,3062,3073,3076,3146,3150,3153,3219,3222,3226,3229,3295,3298,3306,3309,3569,3572,3779,3782,3863,3866,3870,3873,3940,3943,3947,3950,3958,3961,4027,4094,4097,4319,4537,4540,4551,4554,4562,4564,4567,4569,4573,4585,4588,4590],[542,1497,298],{"id":1498},"динамическое-программирование",[546,1500],{":isList":1501,"title":549},"[\"Узнаете про динамическое программирование — метод решения сложных задач, разбиваемых на подзадачи, которые решаются в первую очередь.\",\"Рассматриваются примеры, которые научат вас искать решения новых задач, основанные на методе динамического программирования.\"]",[551,1503,1504],{},[554,1505,1506,1507,1510],{},"В предыдущей статье было о: ",[558,1508,1509],{"href":291},"жадных алгоритмах",".\nЗдесь далее текст пойдёт о динамическом программировании.",[1125,1512,1514],{"id":1513},"задача-о-рюкзаке","Задача о рюкзаке",[551,1516,1517],{},[554,1518,1519],{},"Задача о рюкзаке была описана в предыдущей статье.",[554,1521,1522],{},"Вернёмся к задаче о рюкзаке. У вас есть рюкзак, в котором можно унести товары общим весом до 4 кг.\nЕсть 3 предмета, которые можно положить в рюкзак.",[999,1524,1525,1538],{},[1002,1526,1527],{},[1005,1528,1529,1532,1535],{},[1008,1530,1531],{},"Магнитофон",[1008,1533,1534],{},"Ноутбук",[1008,1536,1537],{},"Гитара",[1015,1539,1540,1551],{},[1005,1541,1542,1545,1548],{},[1020,1543,1544],{},"3000 руб",[1020,1546,1547],{},"2000 руб",[1020,1549,1550],{},"1500 руб",[1005,1552,1553,1556,1559],{},[1020,1554,1555],{},"4 кг",[1020,1557,1558],{},"3 кг",[1020,1560,1561],{},"1 кг",[554,1563,1564],{},"Какие предметы следует положить в рюкзак, чтобы стоимость добычи была максимальной?",[566,1566,1568],{"id":1567},"простое-решение","Простое решение",[554,1570,1571,1572,1629],{},"Простой способ решения выглядит так: вы перебираете все возможные множества товаров и находите множество с максимальной стоимостью.\nТакое решение работает очень медленно. Для 3 предметов приходится обработать 8 множеств, для 4 — 16 и т.д.\nС каждым добавленным предметом количество множеств удваивается. Такое решение будет выполняться за время: ",[582,1573,1575],{"className":1574,"jax":586},[585],[588,1576,1581,1596],{"style":1577,"xmlns":591,"width":1578,"height":1579,"role":594,"focusable":595,"viewBox":1580,"xmlnsXLink":597},"vertical-align: -0.566ex;","5.765ex","2.262ex","0 -750 2548.3 1000",[599,1582,1583,1587,1589,1591,1594],{},[602,1584],{"id":1585,"d":1586},"MJX-1-TEX-I-1D442","M740 435Q740 320 676 213T511 42T304 -22Q207 -22 138 35T51 201Q50 209 50 244Q50 346 98 438T227 601Q351 704 476 704Q514 704 524 703Q621 689 680 617T740 435ZM637 476Q637 565 591 615T476 665Q396 665 322 605Q242 542 200 428T157 216Q157 126 200 73T314 19Q404 19 485 98T608 313Q637 408 637 476Z",[602,1588],{"id":608,"d":609},[602,1590],{"id":624,"d":625},[602,1592],{"id":1593,"d":829},"MJX-1-TEX-I-1D45B",[602,1595],{"id":628,"d":629},[639,1597,1598],{"stroke":641,"fill":641,"stroke-width":642,"transform":643},[639,1599,1600,1606,1611,1624],{"dataMmlNode":646},[639,1601,1602],{"dataMmlNode":674},[664,1603],{"dataC":1604,"xLinkHref":1605},"1D442","#MJX-1-TEX-I-1D442",[639,1607,1609],{"dataMmlNode":662,"transform":1608},"translate(763,0)",[664,1610],{"dataC":666,"xLinkHref":667},[639,1612,1614,1618],{"dataMmlNode":655,"transform":1613},"translate(1152,0)",[639,1615,1616],{"dataMmlNode":681},[664,1617],{"dataC":705,"xLinkHref":706},[639,1619,1621],{"dataMmlNode":674,"transform":1620},"translate(533,363) scale(0.707)",[664,1622],{"dataC":927,"xLinkHref":1623},"#MJX-1-TEX-I-1D45B",[639,1625,1627],{"dataMmlNode":662,"transform":1626},"translate(2159.3,0)",[664,1628],{"dataC":712,"xLinkHref":713},".\nЭто слишком медленно!",[554,1631,1632],{},"Для любого сколько-нибудь значительного количества предметов это неприемлемо долго!\nМожно воспользоваться приближённым решением, но такое решение может существенно не совпадать с оптимальным.\nКак вычислить оптимальное решение? С помощью динамического программирования!",[1125,1634,298],{"id":1635},"динамическое-программирование-1",[554,1637,1638],{},"Рассмотрим как работает данный способ решения задачи.\nПроцедура решения начинается с решения подзадач с постепенным переходом к решению полной задачи.\nВ задаче о рюкзаке начать следует с решения задачи для меньшего рюкзака(или \"подрюкзака\"), а потом на этой основе попытаться решить исходную задачу.",[554,1640,1641],{},"Динамическое программирование — достаточно сложная концепция.\nДополнительные примеры помогут вам в дальнейшем лучше разобраться с этой темой.",[554,1643,1644],{},"Для начала рассмотрим алгоритм в действии.\nКаждый алгоритм динамического программирования начинается с таблицы. Вот как выглядит таблица для задачи о рюкзаке:",[999,1646,1647,1663],{},[1002,1648,1649],{},[1005,1650,1651,1654,1656,1659,1661],{},[1008,1652,1653],{},"-",[1008,1655,988],{},[1008,1657,1658],{},"2",[1008,1660,1055],{},[1008,1662,1025],{},[1015,1664,1665,1677,1689],{},[1005,1666,1667,1669,1671,1673,1675],{},[1020,1668,1537],{},[1020,1670],{},[1020,1672],{},[1020,1674],{},[1020,1676],{},[1005,1678,1679,1681,1683,1685,1687],{},[1020,1680,1531],{},[1020,1682],{},[1020,1684],{},[1020,1686],{},[1020,1688],{},[1005,1690,1691,1693,1695,1697,1699],{},[1020,1692,1534],{},[1020,1694],{},[1020,1696],{},[1020,1698],{},[1020,1700],{},[554,1702,1703],{},"Строки таблицы представляют предметы, а столбцы — ёмкость рюкзака от 1 до 4 кг.\nВсе эти столбы нужны, потому что они упрощают вычисление стоимостей \"подкрюкзаков\".\nВ исходном состоянии таблица пуста. Нам предстоит заполнить каждую ячейку таблицы.\nПосле того как таблица будет заполнена, вы получите ответ на свою задачу.\nПожалуйста, внимательно разберитесь в происходящем. Нарисуйте собственную таблицу.",[574,1705,1537],{"id":1706},"гитара",[554,1708,1709],{},"Точная формула для вычисления значений в таблице будет приведена позднее, а пока ограничимся общим описанием.\nНачнём с первой строки.\nСтрока снабжена пометкой «гитара»; это означает, что вы пытаетесь уложить гитару в рюкзак.\nВ каждой ячейке принимается простое решение:класть гитару в рюкзак или нет?\nПомните: мы пытаемся найти множество элементов с максимальной стоимостью.",[554,1711,1712],{},"В первой ячейке емкость рюкзака равна 1 кг. Гитара также весит 1 кг — значит, она поместится в рюкзак!\nИтак, стоимость этой ячейки составляет 1500₽, а в рюкзаке лежит гитара.\nНачнем заполнять ячейку:",[999,1714,1715,1729],{},[1002,1716,1717],{},[1005,1718,1719,1721,1723,1725,1727],{},[1008,1720,1653],{},[1008,1722,988],{},[1008,1724,1658],{},[1008,1726,1055],{},[1008,1728,1025],{},[1015,1730,1731,1744,1756],{},[1005,1732,1733,1735,1738,1740,1742],{},[1020,1734,1537],{},[1020,1736,1737],{},"1500",[1020,1739],{},[1020,1741],{},[1020,1743],{},[1005,1745,1746,1748,1750,1752,1754],{},[1020,1747,1531],{},[1020,1749],{},[1020,1751],{},[1020,1753],{},[1020,1755],{},[1005,1757,1758,1760,1762,1764,1766],{},[1020,1759,1534],{},[1020,1761],{},[1020,1763],{},[1020,1765],{},[1020,1767],{},[554,1769,1770],{},"По тому же принципу каждая ячейка в таблице содержит список всех элементов, которые помещаются в рюкзаке на данный момент.\nПосмотрим на следующую ячейку. На этот раз емкость рюкзака составляет 2 кг. Понятно, что гитара здесь поместится!",[999,1772,1773,1787],{},[1002,1774,1775],{},[1005,1776,1777,1779,1781,1783,1785],{},[1008,1778,1653],{},[1008,1780,988],{},[1008,1782,1658],{},[1008,1784,1055],{},[1008,1786,1025],{},[1015,1788,1789,1801,1813],{},[1005,1790,1791,1793,1795,1797,1799],{},[1020,1792,1537],{},[1020,1794,1737],{},[1020,1796,1737],{},[1020,1798],{},[1020,1800],{},[1005,1802,1803,1805,1807,1809,1811],{},[1020,1804,1531],{},[1020,1806],{},[1020,1808],{},[1020,1810],{},[1020,1812],{},[1005,1814,1815,1817,1819,1821,1823],{},[1020,1816,1534],{},[1020,1818],{},[1020,1820],{},[1020,1822],{},[1020,1824],{},[554,1826,1827],{},"Процедура повторяется для остальных ячеек строки.\nВспомните, что текущей является первая строка, поэтому выбирать приходится только из одного предмета — гитары.\nСчитайте, что два других предмета пока недоступны.\nПочему все это делается для рюкзаков с емкостью 1, 2 и т.д., если в задаче речь идет о рюкзаке с емкостью 4 кг?\nМетод динамического программирования начинает с малых задач, а затем переходит к большой задаче.\nВы решаете подзадачи, которые помогут в решении большой задачи.\nПосле того как первая строка будет заполнена, таблица будет выглядеть так:",[999,1829,1830,1844],{},[1002,1831,1832],{},[1005,1833,1834,1836,1838,1840,1842],{},[1008,1835,1653],{},[1008,1837,988],{},[1008,1839,1658],{},[1008,1841,1055],{},[1008,1843,1025],{},[1015,1845,1846,1858,1870],{},[1005,1847,1848,1850,1852,1854,1856],{},[1020,1849,1537],{},[1020,1851,1737],{},[1020,1853,1737],{},[1020,1855,1737],{},[1020,1857,1737],{},[1005,1859,1860,1862,1864,1866,1868],{},[1020,1861,1531],{},[1020,1863],{},[1020,1865],{},[1020,1867],{},[1020,1869],{},[1005,1871,1872,1874,1876,1878,1880],{},[1020,1873,1534],{},[1020,1875],{},[1020,1877],{},[1020,1879],{},[1020,1881],{},[554,1883,1884],{},"Помните, что мы стремимся обеспечить максимальную стоимость предметов в рюкзаке.\nЭта строка представляет текущую лучшую оценку максимума.\nИтак, на данный момент из этой строки следует, что для рюкзака с емкостью 4 кг максимальная стоимость предметов составит 1500₽.\nЭто решение неокончательно. В процессе работы алгоритма оценка будет уточняться.",[574,1886,1531],{"id":1887},"магнитофон",[554,1889,1890],{},"Займемся следующей строкой, которая относится к магнитофону.\nТеперь, когда вы перешли ко второй строке, появляется выбор между магнитофоном и гитарой.\nВ каждой строке можно взять предмет этой строки или предметы, находящиеся в верхних строках.\nТаким образом, сейчас нельзя выбрать ноутбук, но можно выбрать магнитофон и\u002Fили гитару.\nНачнем с первой ячейки (рюкзак с емкостью 1 кг).\nТекущая максимальная стоимость предметов, которые можно положить в рюкзак с емкостью 1 кг, составляет 1500₽.\nБрать магнитофон или нет?\nЕмкость рюкзака составляет 1 кг. Поместится туда магнитофон? Нет, он слишком тяжел!\nТак как магнитофон не помещается в рюкзак, максимальная оценка для 1-кг рюкзака остается равной 1500₽.",[999,1892,1893,1907],{},[1002,1894,1895],{},[1005,1896,1897,1899,1901,1903,1905],{},[1008,1898,1653],{},[1008,1900,988],{},[1008,1902,1658],{},[1008,1904,1055],{},[1008,1906,1025],{},[1015,1908,1909,1921,1933],{},[1005,1910,1911,1913,1915,1917,1919],{},[1020,1912,1537],{},[1020,1914,1737],{},[1020,1916,1737],{},[1020,1918,1737],{},[1020,1920,1737],{},[1005,1922,1923,1925,1927,1929,1931],{},[1020,1924,1531],{},[1020,1926,1737],{},[1020,1928],{},[1020,1930],{},[1020,1932],{},[1005,1934,1935,1937,1939,1941,1943],{},[1020,1936,1534],{},[1020,1938],{},[1020,1940],{},[1020,1942],{},[1020,1944],{},[554,1946,1947],{},"То же самое происходит со следующими двумя клетками.\nЕмкость этих рюкзаков составляет 2 и 3 кг соответственно.\nМаксимальная стоимость для обеих ячеек была равна 1500₽.",[999,1949,1950,1964],{},[1002,1951,1952],{},[1005,1953,1954,1956,1958,1960,1962],{},[1008,1955,1653],{},[1008,1957,988],{},[1008,1959,1658],{},[1008,1961,1055],{},[1008,1963,1025],{},[1015,1965,1966,1978,1990],{},[1005,1967,1968,1970,1972,1974,1976],{},[1020,1969,1537],{},[1020,1971,1737],{},[1020,1973,1737],{},[1020,1975,1737],{},[1020,1977,1737],{},[1005,1979,1980,1982,1984,1986,1988],{},[1020,1981,1531],{},[1020,1983,1737],{},[1020,1985,1737],{},[1020,1987,1737],{},[1020,1989],{},[1005,1991,1992,1994,1996,1998,2000],{},[1020,1993,1534],{},[1020,1995],{},[1020,1997],{},[1020,1999],{},[1020,2001],{},[554,2003,2004],{},"Магнитофон все равно не помещается, так что оценка остается неизменной.\nА если емкость рюкзака увеличивается до 4 кг?\nАга, магнитофон наконец-то войдет в рюкзак!\nСтарая максимальная стоимость была равна 1500₽, но если вместо гитары положить магнитофон, она увеличится до 3000₽!\nБерем магнитофон.",[999,2006,2007,2021],{},[1002,2008,2009],{},[1005,2010,2011,2013,2015,2017,2019],{},[1008,2012,1653],{},[1008,2014,988],{},[1008,2016,1658],{},[1008,2018,1055],{},[1008,2020,1025],{},[1015,2022,2023,2035,2048],{},[1005,2024,2025,2027,2029,2031,2033],{},[1020,2026,1537],{},[1020,2028,1737],{},[1020,2030,1737],{},[1020,2032,1737],{},[1020,2034,1737],{},[1005,2036,2037,2039,2041,2043,2045],{},[1020,2038,1531],{},[1020,2040,1737],{},[1020,2042,1737],{},[1020,2044,1737],{},[1020,2046,2047],{},"3000",[1005,2049,2050,2052,2054,2056,2058],{},[1020,2051,1534],{},[1020,2053],{},[1020,2055],{},[1020,2057],{},[1020,2059],{},[554,2061,2062],{},"Оценка только что обновилась! Имея рюкзак емкостью 4 кг, вы можете положить в него товары стоимостью по крайней мере 3000₽.\nИз таблицы видно, что оценка постепенно возрастает.",[574,2064,1534],{"id":2065},"ноутбук",[554,2067,2068],{},"А теперь проделаем то же для ноутбука! Ноутбук весит 3 кг, поэтому он не поместится в рюкзак с емкостью 1 или 2 кг.\nОценка для первых двух ячеек остается на уровне 1500₽.",[999,2070,2071,2085],{},[1002,2072,2073],{},[1005,2074,2075,2077,2079,2081,2083],{},[1008,2076,1653],{},[1008,2078,988],{},[1008,2080,1658],{},[1008,2082,1055],{},[1008,2084,1025],{},[1015,2086,2087,2099,2111],{},[1005,2088,2089,2091,2093,2095,2097],{},[1020,2090,1537],{},[1020,2092,1737],{},[1020,2094,1737],{},[1020,2096,1737],{},[1020,2098,1737],{},[1005,2100,2101,2103,2105,2107,2109],{},[1020,2102,1531],{},[1020,2104,1737],{},[1020,2106,1737],{},[1020,2108,1737],{},[1020,2110,2047],{},[1005,2112,2113,2115,2117,2119,2121],{},[1020,2114,1534],{},[1020,2116,1737],{},[1020,2118,1737],{},[1020,2120],{},[1020,2122],{},[554,2124,2125],{},"Для 3 кг старая оценка составляла 1500₽.\nНо теперь вы можете выбрать ноутбук, который стоит 2000₽.\nСледовательно, новая максимальная оценка равна 2000₽!",[999,2127,2128,2142],{},[1002,2129,2130],{},[1005,2131,2132,2134,2136,2138,2140],{},[1008,2133,1653],{},[1008,2135,988],{},[1008,2137,1658],{},[1008,2139,1055],{},[1008,2141,1025],{},[1015,2143,2144,2156,2168],{},[1005,2145,2146,2148,2150,2152,2154],{},[1020,2147,1537],{},[1020,2149,1737],{},[1020,2151,1737],{},[1020,2153,1737],{},[1020,2155,1737],{},[1005,2157,2158,2160,2162,2164,2166],{},[1020,2159,1531],{},[1020,2161,1737],{},[1020,2163,1737],{},[1020,2165,1737],{},[1020,2167,2047],{},[1005,2169,2170,2172,2174,2176,2179],{},[1020,2171,1534],{},[1020,2173,1737],{},[1020,2175,1737],{},[1020,2177,2178],{},"2000",[1020,2180],{},[554,2182,2183],{},"При 4 кг ситуация становится по-настоящему интересной. Это очень важная часть.\nВ настоящее время оценка составляет 3000₽.\nВ рюкзак можно положить ноутбук, но он стоит всего 2000₽.\nВ соответствии с последней оценкой в свободном месте емкостью в 1 кг можно разместить гитару стоимостью 1500₽.\nСледовательно, настоящее сравнение выглядит так: 3000₽(магнитофон) или (2000₽(ноутбук) + 1500₽(гитара)).\nЗачем мы вычисляем максимальную стоимость для рюкзаков меньшей емкости? Надеюсь, теперь всё ясно!\nЕсли в рюкзаке остается свободное место, вы можете использовать ответы на эти подзадачи для определения того, чем заполнить это пространство.\nВместо магнитофона лучше взять ноутбук + гитару за 3500₽.\nВ завершающем состоянии таблица выглядит так:",[999,2185,2186,2200],{},[1002,2187,2188],{},[1005,2189,2190,2192,2194,2196,2198],{},[1008,2191,1653],{},[1008,2193,988],{},[1008,2195,1658],{},[1008,2197,1055],{},[1008,2199,1025],{},[1015,2201,2202,2214,2226],{},[1005,2203,2204,2206,2208,2210,2212],{},[1020,2205,1537],{},[1020,2207,1737],{},[1020,2209,1737],{},[1020,2211,1737],{},[1020,2213,1737],{},[1005,2215,2216,2218,2220,2222,2224],{},[1020,2217,1531],{},[1020,2219,1737],{},[1020,2221,1737],{},[1020,2223,1737],{},[1020,2225,2047],{},[1005,2227,2228,2230,2232,2234,2236],{},[1020,2229,1534],{},[1020,2231,1737],{},[1020,2233,1737],{},[1020,2235,2178],{},[1020,2237,2238],{},"3500",[554,2240,2241],{},"Итак, мы получили ответ: максимальная стоимость товаров, которые поместятся в рюкзак, равна 3500₽ — для гитары и ноутбука.\nСтоимость каждой ячейки вычисляется по постоянной формуле, которая выглядит так:\nмаксимум из предыдущего элемента или стоимость текущего элемента плюс стоимость оставшегося пространства.\nТаким образом, в данной задаче объединяется решение двух подзадач для решения ещё одной большей задачи.",[1125,2243,2245],{"id":2244},"вопросы-по-задаче","Вопросы по задаче",[554,2247,2248],{},"Ответим на вопросы которую могут возникнуть.",[574,2250,2252],{"id":2251},"что-произойдет-при-добавлении-элемента","Что произойдет при добавлении элемента?",[554,2254,2255],{},"Представьте, что вы увидели четвертый предмет, который тоже можно засунуть в рюкзак!\nВместе со всем предыдущим добром можно также взять смартфон.\nПридется ли пересчитывать все заново с новым предметом? Нет.\nДинамическое программирование последовательно строит решение на основании вашей оценки.\nК настоящему моменту максимальные стоимости выглядят так:",[999,2257,2258,2272],{},[1002,2259,2260],{},[1005,2261,2262,2264,2266,2268,2270],{},[1008,2263,1653],{},[1008,2265,988],{},[1008,2267,1658],{},[1008,2269,1055],{},[1008,2271,1025],{},[1015,2273,2274,2286,2298],{},[1005,2275,2276,2278,2280,2282,2284],{},[1020,2277,1537],{},[1020,2279,1737],{},[1020,2281,1737],{},[1020,2283,1737],{},[1020,2285,1737],{},[1005,2287,2288,2290,2292,2294,2296],{},[1020,2289,1531],{},[1020,2291,1737],{},[1020,2293,1737],{},[1020,2295,1737],{},[1020,2297,2047],{},[1005,2299,2300,2302,2304,2306,2308],{},[1020,2301,1534],{},[1020,2303,1737],{},[1020,2305,1737],{},[1020,2307,2178],{},[1020,2309,2238],{},[554,2311,2312],{},"Это означает, что в рюкзак с емкостью 4 кг можно упаковать товары стоимостью до 3500₽.\nДобавим новую строку для смартфона.",[999,2314,2315,2329],{},[1002,2316,2317],{},[1005,2318,2319,2321,2323,2325,2327],{},[1008,2320,1653],{},[1008,2322,988],{},[1008,2324,1658],{},[1008,2326,1055],{},[1008,2328,1025],{},[1015,2330,2331,2343,2355,2367],{},[1005,2332,2333,2335,2337,2339,2341],{},[1020,2334,1537],{},[1020,2336,1737],{},[1020,2338,1737],{},[1020,2340,1737],{},[1020,2342,1737],{},[1005,2344,2345,2347,2349,2351,2353],{},[1020,2346,1531],{},[1020,2348,1737],{},[1020,2350,1737],{},[1020,2352,1737],{},[1020,2354,2047],{},[1005,2356,2357,2359,2361,2363,2365],{},[1020,2358,1534],{},[1020,2360,1737],{},[1020,2362,1737],{},[1020,2364,2178],{},[1020,2366,2238],{},[1005,2368,2369,2372,2374,2376,2378],{},[1020,2370,2371],{},"Смартфон",[1020,2373],{},[1020,2375],{},[1020,2377],{},[1020,2379,2380],{},"ответ",[554,2382,2383],{},"Оказывается, в таблице появляется новый максимум! Заполним последнюю строку.\nНачнем с первой ячейки. Смартфон сам по себе помещается в рюкзак с емкостью 1 кг.\nСтарый максимум был равен 1500₽, но Смартфон стоит 2000₽.\nЗначит, берем Смартфон.\nВ следующей далее можно разместить смартфон и гитару.",[999,2385,2386,2400],{},[1002,2387,2388],{},[1005,2389,2390,2392,2394,2396,2398],{},[1008,2391,1653],{},[1008,2393,988],{},[1008,2395,1658],{},[1008,2397,1055],{},[1008,2399,1025],{},[1015,2401,2402,2414,2426,2438],{},[1005,2403,2404,2406,2408,2410,2412],{},[1020,2405,1537],{},[1020,2407,1737],{},[1020,2409,1737],{},[1020,2411,1737],{},[1020,2413,1737],{},[1005,2415,2416,2418,2420,2422,2424],{},[1020,2417,1531],{},[1020,2419,1737],{},[1020,2421,1737],{},[1020,2423,1737],{},[1020,2425,2047],{},[1005,2427,2428,2430,2432,2434,2436],{},[1020,2429,1534],{},[1020,2431,1737],{},[1020,2433,1737],{},[1020,2435,2178],{},[1020,2437,2238],{},[1005,2439,2440,2442,2444,2446,2448],{},[1020,2441,2371],{},[1020,2443,2178],{},[1020,2445,2238],{},[1020,2447],{},[1020,2449],{},[554,2451,2452],{},"Для ячейки 3 ничего лучшего, чем снова взять смартфон вместе с гитарой, все равно не найдется.\nА вот в последней ячейке ситуация становится интересной. Текущий максимум до смартфона был равен 3500₽.\nСнова можно взять смартфон, и еще останется свободное место на 3 кг.\nНо эти 3 кг можно заполнить на 2000₽! 2000₽ от смартфона + 2000₽ из старой подзадачи: получается 4000₽. Новый максимум!\nВот как выглядит новая завершающая таблица:",[999,2454,2455,2469],{},[1002,2456,2457],{},[1005,2458,2459,2461,2463,2465,2467],{},[1008,2460,1653],{},[1008,2462,988],{},[1008,2464,1658],{},[1008,2466,1055],{},[1008,2468,1025],{},[1015,2470,2471,2483,2495,2507],{},[1005,2472,2473,2475,2477,2479,2481],{},[1020,2474,1537],{},[1020,2476,1737],{},[1020,2478,1737],{},[1020,2480,1737],{},[1020,2482,1737],{},[1005,2484,2485,2487,2489,2491,2493],{},[1020,2486,1531],{},[1020,2488,1737],{},[1020,2490,1737],{},[1020,2492,1737],{},[1020,2494,2047],{},[1005,2496,2497,2499,2501,2503,2505],{},[1020,2498,1534],{},[1020,2500,1737],{},[1020,2502,1737],{},[1020,2504,2178],{},[1020,2506,2238],{},[1005,2508,2509,2511,2513,2515,2517],{},[1020,2510,2371],{},[1020,2512,2178],{},[1020,2514,2238],{},[1020,2516,2238],{},[1020,2518,2519],{},"4000",[554,2521,2522],{},"Вопрос: может ли значение в столбце уменьшиться? Ответ: нет. При каждой итерации сохраняется текущая оценка максимума.\nЭта оценка ни при каких условиях не может быть меньше предыдущей!",[574,2524,2526],{"id":2525},"что-произойдет-при-изменении-порядка-строк","Что произойдет при изменении порядка строк?",[554,2528,2529],{},"Допустим, строки заполняются в другом порядке: магнитофон, ноутбук, гитара.\nКак будет выглядеть таблица? Изменится ли ответ? Заполните таблицу самостоятельно и убедитесь — ответ не изменился.\nОтвет не зависит от порядка строк.",[574,2531,2533],{"id":2532},"можно-ли-заполнять-таблицу-по-столбцам-а-не-по-строкам","Можно ли заполнять таблицу по столбцам, а не по строкам?",[554,2535,2536],{},"В данной задаче это ни на что не влияет, но в других задачах возможны изменения.",[574,2538,2540],{"id":2539},"что-произойдет-при-добавлении-меньшего-элемента","Что произойдет при добавлении меньшего элемента?",[554,2542,2543],{},"Допустим, вы можете выбрать ожерелье, которое весит 0,5 кг и стоит 1000₽.\nИзначально наша структура таблицы предполагает, что все веса являются целыми числами.\nТеперь вы решаете взять ожерелье. Остается еще 3,5 кг.\nКакую максимальную стоимость можно разместить в объеме 3,5 кг? Неизвестно!\nМы вычисляли стоимость только для рюкзаков с емкостью 1, 2, 3 и 4 кг.\nТеперь придется определять стоимость для рюкзака на 3,5 кг.\nИз-за ожерелья приходится повысить точность представления весов, поэтому таблица должна измениться.",[999,2545,2546,2572],{},[1002,2547,2548],{},[1005,2549,2550,2552,2555,2557,2560,2562,2565,2567,2570],{},[1008,2551,1653],{},[1008,2553,2554],{},"0.5",[1008,2556,988],{},[1008,2558,2559],{},"1.5",[1008,2561,1658],{},[1008,2563,2564],{},"2.5",[1008,2566,1055],{},[1008,2568,2569],{},"3.5",[1008,2571,1025],{},[1015,2573,2574,2594,2614,2634],{},[1005,2575,2576,2578,2580,2582,2584,2586,2588,2590,2592],{},[1020,2577,1537],{},[1020,2579],{},[1020,2581],{},[1020,2583],{},[1020,2585],{},[1020,2587],{},[1020,2589],{},[1020,2591],{},[1020,2593],{},[1005,2595,2596,2598,2600,2602,2604,2606,2608,2610,2612],{},[1020,2597,1531],{},[1020,2599],{},[1020,2601],{},[1020,2603],{},[1020,2605],{},[1020,2607],{},[1020,2609],{},[1020,2611],{},[1020,2613],{},[1005,2615,2616,2618,2620,2622,2624,2626,2628,2630,2632],{},[1020,2617,1534],{},[1020,2619],{},[1020,2621],{},[1020,2623],{},[1020,2625],{},[1020,2627],{},[1020,2629],{},[1020,2631],{},[1020,2633],{},[1005,2635,2636,2639,2641,2643,2645,2647,2649,2651,2653],{},[1020,2637,2638],{},"Ожерелье",[1020,2640],{},[1020,2642],{},[1020,2644],{},[1020,2646],{},[1020,2648],{},[1020,2650],{},[1020,2652],{},[1020,2654],{},[574,2656,2658],{"id":2657},"можно-ли-взять-часть-предмета","Можно ли взять часть предмета?",[554,2660,2661],{},"Допустим, вы наполняете рюкзак в продуктовом магазине. Вы можете взять мешки с чечевицей и рисом.\nЕсли весь мешок не помещается, его можно открыть и отсыпать столько, сколько унесете.\nВ этом случае вы уже не действуете по принципу «все или ничего» — можно взять только часть предмета.\nКак решить такую задачу методом динамического программирования?\nОтвет: никак. В решении, полученном методом динамического программирования, вы либо берете предмет, либо не берете.\nАлгоритм не предусматривает возможности взять половину предмета.\nОднако проблема легко решается с помощью жадного алгоритма!\nСначала вы берете самый ценный предмет — настолько бóльшую его часть, насколько возможно.\nКогда самый ценный предмет будет исчерпан, вы берете максимально возможную часть следующего по ценности предмета и т.д.",[566,2663,2665],{"id":2664},"оптимизация-туристического-маршрута","Оптимизация туристического маршрута",[554,2667,2668],{},"Представьте, что вы приехали в Лондон на выходные. У вас два дня, а мест, которые хочется посетить, слишком много.\nПобывать везде не получится, поэтому вы составляете список.\nДля каждой достопримечательности, которую вы захотите увидеть, вы указываете, сколько времени займет осмотр и насколько сильно вы хотите ее увидеть.\nСможете ли вы построить оптимальный туристический маршрут на основании этого списка?\nДа это все та же задача о рюкзаке! Вместо ограниченной емкости рюкзака — ограниченное время.\nВместо магнитофонов и ноутбуков — список мест, которые вы хотите посетить.",[999,2670,2671,2683],{},[1002,2672,2673],{},[1005,2674,2675,2678,2681],{},[1008,2676,2677],{},"Достопримечательность",[1008,2679,2680],{},"Время",[1008,2682,1013],{},[1015,2684,2685,2696,2707,2717,2727],{},[1005,2686,2687,2690,2693],{},[1020,2688,2689],{},"Вестминстерское аббатство",[1020,2691,2692],{},"1\u002F2 дня",[1020,2694,2695],{},"7",[1005,2697,2698,2701,2704],{},[1020,2699,2700],{},"Национальная галерея",[1020,2702,2703],{},"1 день",[1020,2705,2706],{},"9",[1005,2708,2709,2712,2714],{},[1020,2710,2711],{},"Театр",[1020,2713,2692],{},[1020,2715,2716],{},"6",[1005,2718,2719,2722,2725],{},[1020,2720,2721],{},"Музей",[1020,2723,2724],{},"2 дня",[1020,2726,2706],{},[1005,2728,2729,2732,2734],{},[1020,2730,2731],{},"Собор св. Павла",[1020,2733,2692],{},[1020,2735,2736],{},"8",[554,2738,2739],{},"Нарисуйте таблицу динамического программирования для списка, прежде чем двигаться дальше.\nВот как должна выглядеть эта таблица:",[999,2741,2742,2758],{},[1002,2743,2744],{},[1005,2745,2746,2748,2751,2753,2756],{},[1008,2747,1653],{},[1008,2749,2750],{},"1\u002F2",[1008,2752,988],{},[1008,2754,2755],{},"1 1\u002F2",[1008,2757,1658],{},[1015,2759,2760,2773,2785,2798,2810],{},[1005,2761,2762,2765,2767,2769,2771],{},[1020,2763,2764],{},"Вестминистер",[1020,2766],{},[1020,2768],{},[1020,2770],{},[1020,2772],{},[1005,2774,2775,2777,2779,2781,2783],{},[1020,2776,2711],{},[1020,2778],{},[1020,2780],{},[1020,2782],{},[1020,2784],{},[1005,2786,2787,2790,2792,2794,2796],{},[1020,2788,2789],{},"Галерея",[1020,2791],{},[1020,2793],{},[1020,2795],{},[1020,2797],{},[1005,2799,2800,2802,2804,2806,2808],{},[1020,2801,2721],{},[1020,2803],{},[1020,2805],{},[1020,2807],{},[1020,2809],{},[1005,2811,2812,2815,2817,2819,2821],{},[1020,2813,2814],{},"Собор",[1020,2816],{},[1020,2818],{},[1020,2820],{},[1020,2822],{},[554,2824,2825],{},"Вы изобразили ее правильно? Теперь заполните. Какие достопримечательности вы выберете? Ответ: аббатство, галерея, собор.",[999,2827,2828,2842],{},[1002,2829,2830],{},[1005,2831,2832,2834,2836,2838,2840],{},[1008,2833,1653],{},[1008,2835,2750],{},[1008,2837,988],{},[1008,2839,2755],{},[1008,2841,1658],{},[1015,2843,2844,2856,2869,2883,2895],{},[1005,2845,2846,2848,2850,2852,2854],{},[1020,2847,2764],{},[1020,2849,2695],{},[1020,2851,2695],{},[1020,2853,2695],{},[1020,2855,2695],{},[1005,2857,2858,2860,2862,2865,2867],{},[1020,2859,2711],{},[1020,2861,2695],{},[1020,2863,2864],{},"13",[1020,2866,2864],{},[1020,2868,2864],{},[1005,2870,2871,2873,2875,2877,2880],{},[1020,2872,2789],{},[1020,2874,2695],{},[1020,2876,2864],{},[1020,2878,2879],{},"16",[1020,2881,2882],{},"22",[1005,2884,2885,2887,2889,2891,2893],{},[1020,2886,2721],{},[1020,2888,2695],{},[1020,2890,2864],{},[1020,2892,2879],{},[1020,2894,2882],{},[1005,2896,2897,2899,2901,2904,2907],{},[1020,2898,2814],{},[1020,2900,2736],{},[1020,2902,2903],{},"15",[1020,2905,2906],{},"21",[1020,2908,2909],{},"24",[574,2911,2913],{"id":2912},"взаимозависимые-элементы","Взаимозависимые элементы",[554,2915,2916],{},"Предположим, вы хотите посетить Париж и добавили в свой список пару элементов.",[999,2918,2919,2929],{},[1002,2920,2921],{},[1005,2922,2923,2925,2927],{},[1008,2924,2677],{},[1008,2926,2680],{},[1008,2928,1013],{},[1015,2930,2931,2939,2947,2955,2963,2971,2981,2990],{},[1005,2932,2933,2935,2937],{},[1020,2934,2689],{},[1020,2936,2692],{},[1020,2938,2695],{},[1005,2940,2941,2943,2945],{},[1020,2942,2700],{},[1020,2944,2703],{},[1020,2946,2706],{},[1005,2948,2949,2951,2953],{},[1020,2950,2711],{},[1020,2952,2692],{},[1020,2954,2716],{},[1005,2956,2957,2959,2961],{},[1020,2958,2721],{},[1020,2960,2724],{},[1020,2962,2706],{},[1005,2964,2965,2967,2969],{},[1020,2966,2731],{},[1020,2968,2692],{},[1020,2970,2736],{},[1005,2972,2973,2976,2979],{},[1020,2974,2975],{},"Эйфелева башня",[1020,2977,2978],{},"1 1\u002F2 дня",[1020,2980,2736],{},[1005,2982,2983,2986,2988],{},[1020,2984,2985],{},"Лувр",[1020,2987,2978],{},[1020,2989,2706],{},[1005,2991,2992,2995,2997],{},[1020,2993,2994],{},"Нотр-дам",[1020,2996,2978],{},[1020,2998,2695],{},[554,3000,3001],{},"На их посещение потребуется много времени, потому что сначала придется приехать из Лондона в Париж.\nПереезд отнимает полдня. Если вы захотите посмотреть все 3 достопримечательности, осмотр займет 4,5 дня.\nНебольшая поправка: не обязательно приезжать в Париж ради каждой достопримечательности.\nПосле того как вы там окажетесь, каждый последующий элемент займет всего один день.\nСледовательно, потребуется 1 день на каждую достопримечательность + 1 день на переезды = 3,5 дня, а не 4,5.",[554,3003,3004],{},"Если вы положите Эйфелеву башню в свой «рюкзак», то Лувр станет «дешевле» — он займет всего 1 день вместо 1,5.\nКак смоделировать это обстоятельство в динамическом программировании? Ответ: никак.\nДинамическое программирование — мощный метод, способный решать подзадачи и использовать полученные ответы для решения большой задачи.\nДинамическое программирование работает только в том случае, если каждая подзадача автономна, то есть не зависит от других подзадач.\nИз этого следует, что учесть поездки в Париж в алгоритме динамического программирования не удастся.",[574,3006,3008],{"id":3007},"может-ли-оказаться-что-решение-требует-более-двух-подрюкзаков","Может ли оказаться, что решение требует более двух «подрюкзаков»?",[554,3010,3011],{},"Может оказаться, что в лучшем решении должны отбираться больше двух элементов.\nВ текущем варианте алгоритма объединяются не более двух «подрюкзаков» — больше двух их не бывает.\nОднако вполне возможно, что у этих «подрюкзаков» будут собственные «подрюкзаки».",[574,3013,3015],{"id":3014},"возможно-ли-что-при-лучшем-решении-в-рюкзаке-остается-пустое-место","Возможно ли, что при лучшем решении в рюкзаке остается пустое место?",[554,3017,3018],{},"Да. Представьте, что вы можете также положить в рюкзак бриллиант.\nБриллиант очень крупный: он весит целых 3,5 кг и стоит 1 миллиард долларов — намного больше, чем любые другие предметы.\nБезусловно, нужно брать именно его!\nНо в рюкзаке остается еще пустое место на 0,5 кг, и в нем ничего не поместится.",[566,3020,3022],{"id":3021},"выводы","Выводы",[554,3024,3025],{},"Мы рассмотрели одну задачу динамического программирования. Какие выводы из нее можно сделать?",[1060,3027,3028,3031],{},[1063,3029,3030],{},"Динамическое программирование применяется для оптимизации какой-либо характеристики при заданных ограничениях. В задаче о рюкзаке требуется максимизировать стоимость отобранных предметов с ограничениями по емкости рюкзака.",[1063,3032,3033],{},"Динамическое программирование работает только в ситуациях, в которых задача может быть разбита на автономные подзадачи, не зависящие друг от друга.",[554,3035,3036],{},"Построить решение на базе динамического программирования бывает непросто. Несколько общих рекомендаций:",[1060,3038,3039,3042,3045],{},[1063,3040,3041],{},"в каждом решении из области динамического программирования строится таблица;",[1063,3043,3044],{},"значения ячеек таблицы обычно соответствуют оптимизируемой характеристике. Для задачи о рюкзаке значения представляли общую стоимость товаров;",[1063,3046,3047],{},"каждая ячейка представляет подзадачу, поэтому вы должны подумать о том, как разбить задачу на подзадачи. Это поможет вам определиться с осями.",[566,3049,3051],{"id":3050},"ещё-пример-задачи","Ещё пример задачи",[554,3053,3054],{},"Допустим, вы открыли сайт dictionary.com. Пользователь вводит слово, а сайт возвращает определение.\nНо если пользователь ввел несуществующее слово, нужно предположить, какое слово имелось в виду.\nАлексей ищет определение «fish», но он случайно ввел «hish». Такого слова в словаре нет, но зато у вас есть список похожих слов.\nКакое слово он хотел ввести на самом деле: fish или например, vista?",[574,3056,3058],{"id":3057},"построение-таблицы","Построение таблицы",[554,3060,3061],{},"Как должна выглядеть таблица для этой задачи? Вы должны ответить на следующие вопросы.",[1060,3063,3064,3067,3070],{},[1063,3065,3066],{},"Какие значения должны содержаться в ячейках?",[1063,3068,3069],{},"Как разбить эту задачу на подзадачи?",[1063,3071,3072],{},"Каков смысл осей таблицы?",[554,3074,3075],{},"В динамическом программировании вы пытаетесь максимизировать некоторую характеристику.\nВ данном случае ищется самая длинная подстрока, общая в двух словах.\nКакую общую подстроку содержат hish и fish? А как насчет hish и vista? Именно это требуется вычислить.\nКак говорилось ранее, значения в ячейках обычно представляют ту характеристику, которую вы пытаетесь оптимизировать.\nВероятно, в данном случае этой характеристикой будет число: длина самой длинной подстроки, общей для двух строк.\nКак разделить эту задачу на подзадачи? Например, можно заняться сравнением подстрок.\nВместо того чтобы сравнивать hish и fish, можно сначала сравнить his и fis.\nКаждая ячейка будет содержать длину самой длинной подстроки, общей для двух подстрок.\nТакое решение также подсказывает, что строками и столбцами таблицы, вероятно, будут два слова.\nА значит, таблица будет выглядеть примерно так:",[999,3077,3078,3095],{},[1002,3079,3080],{},[1005,3081,3082,3084,3087,3090,3093],{},[1008,3083,1653],{},[1008,3085,3086],{},"H",[1008,3088,3089],{},"I",[1008,3091,3092],{},"S",[1008,3094,3086],{},[1015,3096,3097,3110,3122,3134],{},[1005,3098,3099,3102,3104,3106,3108],{},[1020,3100,3101],{},"F",[1020,3103],{},[1020,3105],{},[1020,3107],{},[1020,3109],{},[1005,3111,3112,3114,3116,3118,3120],{},[1020,3113,3089],{},[1020,3115],{},[1020,3117],{},[1020,3119],{},[1020,3121],{},[1005,3123,3124,3126,3128,3130,3132],{},[1020,3125,3092],{},[1020,3127],{},[1020,3129],{},[1020,3131],{},[1020,3133],{},[1005,3135,3136,3138,3140,3142,3144],{},[1020,3137,3086],{},[1020,3139],{},[1020,3141],{},[1020,3143],{},[1020,3145],{},[574,3147,3149],{"id":3148},"заполнение-таблицы","Заполнение таблицы",[554,3151,3152],{},"Сейчас вы уже достаточно хорошо представляете, как должна выглядеть таблица.\nПо какой формуле заполняются ячейки таблицы?\nМы можем немного упростить свою задачу, потому что уже знаем решение — у hish и fish имеется общая подстрока длины 3: ish.\nОднако этот факт ничего не говорит о том, какая формула должна использоваться.\nПо правде говоря, простого способа вычислить формулу для данного случая не существует.\nВам придется экспериментировать и искать работоспособное решение.\nИногда алгоритм предоставляет не точный рецепт, а основу, на которую вы наращиваете свою идею.\nПопробуйте предложить решение этой задачи самостоятельно. Часть таблицы выглядит так:",[999,3154,3155,3169],{},[1002,3156,3157],{},[1005,3158,3159,3161,3163,3165,3167],{},[1008,3160,1653],{},[1008,3162,3086],{},[1008,3164,3089],{},[1008,3166,3092],{},[1008,3168,3086],{},[1015,3170,3171,3183,3195,3207],{},[1005,3172,3173,3175,3177,3179,3181],{},[1020,3174,3101],{},[1020,3176,642],{},[1020,3178,642],{},[1020,3180],{},[1020,3182],{},[1005,3184,3185,3187,3189,3191,3193],{},[1020,3186,3089],{},[1020,3188],{},[1020,3190],{},[1020,3192],{},[1020,3194],{},[1005,3196,3197,3199,3201,3203,3205],{},[1020,3198,3092],{},[1020,3200],{},[1020,3202],{},[1020,3204,1658],{},[1020,3206,642],{},[1005,3208,3209,3211,3213,3215,3217],{},[1020,3210,3086],{},[1020,3212],{},[1020,3214],{},[1020,3216],{},[1020,3218,1055],{},[554,3220,3221],{},"Попытайтесь вывести формулу самостоятельно, прежде чем продолжить читать.",[574,3223,3225],{"id":3224},"решение","Решение",[554,3227,3228],{},"Итоговая версия таблицы выглядит так:",[999,3230,3231,3245],{},[1002,3232,3233],{},[1005,3234,3235,3237,3239,3241,3243],{},[1008,3236,1653],{},[1008,3238,3086],{},[1008,3240,3089],{},[1008,3242,3092],{},[1008,3244,3086],{},[1015,3246,3247,3259,3271,3283],{},[1005,3248,3249,3251,3253,3255,3257],{},[1020,3250,3101],{},[1020,3252,642],{},[1020,3254,642],{},[1020,3256,642],{},[1020,3258,642],{},[1005,3260,3261,3263,3265,3267,3269],{},[1020,3262,3089],{},[1020,3264,642],{},[1020,3266,988],{},[1020,3268,642],{},[1020,3270,642],{},[1005,3272,3273,3275,3277,3279,3281],{},[1020,3274,3092],{},[1020,3276,642],{},[1020,3278,642],{},[1020,3280,1658],{},[1020,3282,642],{},[1005,3284,3285,3287,3289,3291,3293],{},[1020,3286,3086],{},[1020,3288,988],{},[1020,3290,642],{},[1020,3292,642],{},[1020,3294,1055],{},[554,3296,3297],{},"Формула заполнения ячеек:",[1143,3299,3300,3303],{},[1063,3301,3302],{},"Если буквы не совпадают, значение равно 0;",[1063,3304,3305],{},"Если буквы совпадают, то значение равно значению ячейки наверху слева +1.",[554,3307,3308],{},"На Python эта формула реализуется так:",[3310,3311,3315],"pre",{"className":3312,"code":3313,"language":3314,"meta":982,"style":982},"language-python shiki shiki-themes github-light","dp_table_hish = [\"h\", \"i\", \"s\", \"h\"]\ndp_table_fish = [\"f\", \"i\", \"s\", \"h\"]\ndp_table = [[0 for i in range(len(dp_table_hish))] for i in range(len(dp_table_fish))]\nfor i in range(0, len(dp_table_fish)):\n    for j in range(0, len(dp_table_hish)):\n        if dp_table_hish[j] == dp_table_fish[i]:  # Буквы совпадают\n            dp_table[i][j] = dp_table[i-1][j-1] + 1\n        else:  # Буквы не совпали\n            dp_table[i][j] = 0\nfor i in dp_table:\n    print(i)\n","python",[3316,3317,3318,3356,3382,3432,3453,3476,3495,3526,3538,3548,3560],"code",{"__ignoreMap":982},[3319,3320,3323,3327,3331,3334,3338,3341,3344,3346,3349,3351,3353],"span",{"class":3321,"line":3322},"line",1,[3319,3324,3326],{"class":3325},"sgsFI","dp_table_hish ",[3319,3328,3330],{"class":3329},"sD7c4","=",[3319,3332,3333],{"class":3325}," [",[3319,3335,3337],{"class":3336},"sYBdl","\"h\"",[3319,3339,3340],{"class":3325},", ",[3319,3342,3343],{"class":3336},"\"i\"",[3319,3345,3340],{"class":3325},[3319,3347,3348],{"class":3336},"\"s\"",[3319,3350,3340],{"class":3325},[3319,3352,3337],{"class":3336},[3319,3354,3355],{"class":3325},"]\n",[3319,3357,3358,3361,3363,3365,3368,3370,3372,3374,3376,3378,3380],{"class":3321,"line":1443},[3319,3359,3360],{"class":3325},"dp_table_fish ",[3319,3362,3330],{"class":3329},[3319,3364,3333],{"class":3325},[3319,3366,3367],{"class":3336},"\"f\"",[3319,3369,3340],{"class":3325},[3319,3371,3343],{"class":3336},[3319,3373,3340],{"class":3325},[3319,3375,3348],{"class":3336},[3319,3377,3340],{"class":3325},[3319,3379,3337],{"class":3336},[3319,3381,3355],{"class":3325},[3319,3383,3384,3387,3389,3392,3395,3398,3401,3404,3407,3410,3413,3416,3419,3421,3423,3425,3427,3429],{"class":3321,"line":1458},[3319,3385,3386],{"class":3325},"dp_table ",[3319,3388,3330],{"class":3329},[3319,3390,3391],{"class":3325}," [[",[3319,3393,642],{"class":3394},"sYu0t",[3319,3396,3397],{"class":3329}," for",[3319,3399,3400],{"class":3325}," i ",[3319,3402,3403],{"class":3329},"in",[3319,3405,3406],{"class":3394}," range",[3319,3408,3409],{"class":3325},"(",[3319,3411,3412],{"class":3394},"len",[3319,3414,3415],{"class":3325},"(dp_table_hish))] ",[3319,3417,3418],{"class":3329},"for",[3319,3420,3400],{"class":3325},[3319,3422,3403],{"class":3329},[3319,3424,3406],{"class":3394},[3319,3426,3409],{"class":3325},[3319,3428,3412],{"class":3394},[3319,3430,3431],{"class":3325},"(dp_table_fish))]\n",[3319,3433,3434,3436,3438,3440,3442,3444,3446,3448,3450],{"class":3321,"line":1449},[3319,3435,3418],{"class":3329},[3319,3437,3400],{"class":3325},[3319,3439,3403],{"class":3329},[3319,3441,3406],{"class":3394},[3319,3443,3409],{"class":3325},[3319,3445,642],{"class":3394},[3319,3447,3340],{"class":3325},[3319,3449,3412],{"class":3394},[3319,3451,3452],{"class":3325},"(dp_table_fish)):\n",[3319,3454,3455,3458,3461,3463,3465,3467,3469,3471,3473],{"class":3321,"line":1444},[3319,3456,3457],{"class":3329},"    for",[3319,3459,3460],{"class":3325}," j ",[3319,3462,3403],{"class":3329},[3319,3464,3406],{"class":3394},[3319,3466,3409],{"class":3325},[3319,3468,642],{"class":3394},[3319,3470,3340],{"class":3325},[3319,3472,3412],{"class":3394},[3319,3474,3475],{"class":3325},"(dp_table_hish)):\n",[3319,3477,3479,3482,3485,3488,3491],{"class":3321,"line":3478},6,[3319,3480,3481],{"class":3329},"        if",[3319,3483,3484],{"class":3325}," dp_table_hish[j] ",[3319,3486,3487],{"class":3329},"==",[3319,3489,3490],{"class":3325}," dp_table_fish[i]:  ",[3319,3492,3494],{"class":3493},"sAwPA","# Буквы совпадают\n",[3319,3496,3498,3501,3503,3506,3508,3510,3513,3515,3517,3520,3523],{"class":3321,"line":3497},7,[3319,3499,3500],{"class":3325},"            dp_table[i][j] ",[3319,3502,3330],{"class":3329},[3319,3504,3505],{"class":3325}," dp_table[i",[3319,3507,1653],{"class":3329},[3319,3509,988],{"class":3394},[3319,3511,3512],{"class":3325},"][j",[3319,3514,1653],{"class":3329},[3319,3516,988],{"class":3394},[3319,3518,3519],{"class":3325},"] ",[3319,3521,3522],{"class":3329},"+",[3319,3524,3525],{"class":3394}," 1\n",[3319,3527,3529,3532,3535],{"class":3321,"line":3528},8,[3319,3530,3531],{"class":3329},"        else",[3319,3533,3534],{"class":3325},":  ",[3319,3536,3537],{"class":3493},"# Буквы не совпали\n",[3319,3539,3541,3543,3545],{"class":3321,"line":3540},9,[3319,3542,3500],{"class":3325},[3319,3544,3330],{"class":3329},[3319,3546,3547],{"class":3394}," 0\n",[3319,3549,3551,3553,3555,3557],{"class":3321,"line":3550},10,[3319,3552,3418],{"class":3329},[3319,3554,3400],{"class":3325},[3319,3556,3403],{"class":3329},[3319,3558,3559],{"class":3325}," dp_table:\n",[3319,3561,3563,3566],{"class":3321,"line":3562},11,[3319,3564,3565],{"class":3394},"    print",[3319,3567,3568],{"class":3325},"(i)\n",[554,3570,3571],{},"Аналогично для строк hish и vista:",[3310,3573,3575],{"className":3312,"code":3574,"language":3314,"meta":982,"style":982},"dp_table_hish = [\"h\", \"i\", \"s\", \"h\"]\ndp_table_vista = [\"v\", \"i\", \"s\", \"t\", \"a\"]\ndp_table = [[0 for i in range(len(dp_table_hish))] for i in range(len(dp_table_vista))]\nfor i in range(0, len(dp_table_vista)):\n    for j in range(0, len(dp_table_hish)):\n        if dp_table_hish[j] == dp_table_vista[i]:\n            dp_table[i][j] = dp_table[i-1][j-1] + 1\n        else:\n            dp_table[i][j] = 0\nfor i in dp_table:\n    print(i)\n",[3316,3576,3577,3601,3633,3672,3693,3713,3724,3748,3755,3763,3773],{"__ignoreMap":982},[3319,3578,3579,3581,3583,3585,3587,3589,3591,3593,3595,3597,3599],{"class":3321,"line":3322},[3319,3580,3326],{"class":3325},[3319,3582,3330],{"class":3329},[3319,3584,3333],{"class":3325},[3319,3586,3337],{"class":3336},[3319,3588,3340],{"class":3325},[3319,3590,3343],{"class":3336},[3319,3592,3340],{"class":3325},[3319,3594,3348],{"class":3336},[3319,3596,3340],{"class":3325},[3319,3598,3337],{"class":3336},[3319,3600,3355],{"class":3325},[3319,3602,3603,3606,3608,3610,3613,3615,3617,3619,3621,3623,3626,3628,3631],{"class":3321,"line":1443},[3319,3604,3605],{"class":3325},"dp_table_vista ",[3319,3607,3330],{"class":3329},[3319,3609,3333],{"class":3325},[3319,3611,3612],{"class":3336},"\"v\"",[3319,3614,3340],{"class":3325},[3319,3616,3343],{"class":3336},[3319,3618,3340],{"class":3325},[3319,3620,3348],{"class":3336},[3319,3622,3340],{"class":3325},[3319,3624,3625],{"class":3336},"\"t\"",[3319,3627,3340],{"class":3325},[3319,3629,3630],{"class":3336},"\"a\"",[3319,3632,3355],{"class":3325},[3319,3634,3635,3637,3639,3641,3643,3645,3647,3649,3651,3653,3655,3657,3659,3661,3663,3665,3667,3669],{"class":3321,"line":1458},[3319,3636,3386],{"class":3325},[3319,3638,3330],{"class":3329},[3319,3640,3391],{"class":3325},[3319,3642,642],{"class":3394},[3319,3644,3397],{"class":3329},[3319,3646,3400],{"class":3325},[3319,3648,3403],{"class":3329},[3319,3650,3406],{"class":3394},[3319,3652,3409],{"class":3325},[3319,3654,3412],{"class":3394},[3319,3656,3415],{"class":3325},[3319,3658,3418],{"class":3329},[3319,3660,3400],{"class":3325},[3319,3662,3403],{"class":3329},[3319,3664,3406],{"class":3394},[3319,3666,3409],{"class":3325},[3319,3668,3412],{"class":3394},[3319,3670,3671],{"class":3325},"(dp_table_vista))]\n",[3319,3673,3674,3676,3678,3680,3682,3684,3686,3688,3690],{"class":3321,"line":1449},[3319,3675,3418],{"class":3329},[3319,3677,3400],{"class":3325},[3319,3679,3403],{"class":3329},[3319,3681,3406],{"class":3394},[3319,3683,3409],{"class":3325},[3319,3685,642],{"class":3394},[3319,3687,3340],{"class":3325},[3319,3689,3412],{"class":3394},[3319,3691,3692],{"class":3325},"(dp_table_vista)):\n",[3319,3694,3695,3697,3699,3701,3703,3705,3707,3709,3711],{"class":3321,"line":1444},[3319,3696,3457],{"class":3329},[3319,3698,3460],{"class":3325},[3319,3700,3403],{"class":3329},[3319,3702,3406],{"class":3394},[3319,3704,3409],{"class":3325},[3319,3706,642],{"class":3394},[3319,3708,3340],{"class":3325},[3319,3710,3412],{"class":3394},[3319,3712,3475],{"class":3325},[3319,3714,3715,3717,3719,3721],{"class":3321,"line":3478},[3319,3716,3481],{"class":3329},[3319,3718,3484],{"class":3325},[3319,3720,3487],{"class":3329},[3319,3722,3723],{"class":3325}," dp_table_vista[i]:\n",[3319,3725,3726,3728,3730,3732,3734,3736,3738,3740,3742,3744,3746],{"class":3321,"line":3497},[3319,3727,3500],{"class":3325},[3319,3729,3330],{"class":3329},[3319,3731,3505],{"class":3325},[3319,3733,1653],{"class":3329},[3319,3735,988],{"class":3394},[3319,3737,3512],{"class":3325},[3319,3739,1653],{"class":3329},[3319,3741,988],{"class":3394},[3319,3743,3519],{"class":3325},[3319,3745,3522],{"class":3329},[3319,3747,3525],{"class":3394},[3319,3749,3750,3752],{"class":3321,"line":3528},[3319,3751,3531],{"class":3329},[3319,3753,3754],{"class":3325},":\n",[3319,3756,3757,3759,3761],{"class":3321,"line":3540},[3319,3758,3500],{"class":3325},[3319,3760,3330],{"class":3329},[3319,3762,3547],{"class":3394},[3319,3764,3765,3767,3769,3771],{"class":3321,"line":3550},[3319,3766,3418],{"class":3329},[3319,3768,3400],{"class":3325},[3319,3770,3403],{"class":3329},[3319,3772,3559],{"class":3325},[3319,3774,3775,3777],{"class":3321,"line":3562},[3319,3776,3565],{"class":3394},[3319,3778,3568],{"class":3325},[554,3780,3781],{},"Таблица:",[999,3783,3784,3798],{},[1002,3785,3786],{},[1005,3787,3788,3790,3792,3794,3796],{},[1008,3789,1653],{},[1008,3791,3086],{},[1008,3793,3089],{},[1008,3795,3092],{},[1008,3797,3086],{},[1015,3799,3800,3813,3825,3837,3850],{},[1005,3801,3802,3805,3807,3809,3811],{},[1020,3803,3804],{},"V",[1020,3806,642],{},[1020,3808,642],{},[1020,3810,642],{},[1020,3812,642],{},[1005,3814,3815,3817,3819,3821,3823],{},[1020,3816,3089],{},[1020,3818,642],{},[1020,3820,988],{},[1020,3822,642],{},[1020,3824,642],{},[1005,3826,3827,3829,3831,3833,3835],{},[1020,3828,3092],{},[1020,3830,642],{},[1020,3832,642],{},[1020,3834,1658],{},[1020,3836,642],{},[1005,3838,3839,3842,3844,3846,3848],{},[1020,3840,3841],{},"T",[1020,3843,642],{},[1020,3845,642],{},[1020,3847,642],{},[1020,3849,642],{},[1005,3851,3852,3855,3857,3859,3861],{},[1020,3853,3854],{},"A",[1020,3856,642],{},[1020,3858,642],{},[1020,3860,642],{},[1020,3862,642],{},[554,3864,3865],{},"Важный момент: в этой задаче окончательное решение далеко не всегда находится в последней ячейке!\nВ задаче о рюкзаке последняя ячейка всегда содержит окончательное решение.\nНо в задаче поиска самой длинной общей подстроки решение определяется самым большим числом в таблице — и это может быть не последняя, а какая-то другая ячейка.\nВернемся к исходному вопросу: какая строка ближе к hish? У строк hish и fish есть общая подстрока длиной в три буквы.\nУ hish и vista есть общая подстрока из двух букв. Скорее всего, Алексей хотел ввести строку fish.",[566,3867,3869],{"id":3868},"самая-длинная-общая-подпоследовательность","Самая длинная общая подпоследовательность",[554,3871,3872],{},"Предположим, Алексей ввел строку fosh. Какое слово он имел в виду: fish или fort?\nСравним строки, по способу выше, длину общей подстроки.\nОкажется, что длина подстрок одинакова: две буквы! Но fosh при этом ближе к fish.\nМы сравниваем самую длинную общую подстроку, а на самом деле нужно сравнивать самую длинную общую подпоследовательность: количество букв в последовательности, общих для двух слов.\nКак вычислить самую длинную общую подпоследовательность?\nНиже приведена частично заполненная таблица для fish и fosh:",[999,3874,3875,3890],{},[1002,3876,3877],{},[1005,3878,3879,3881,3883,3886,3888],{},[1008,3880,1653],{},[1008,3882,3101],{},[1008,3884,3885],{},"O",[1008,3887,3092],{},[1008,3889,3086],{},[1015,3891,3892,3904,3916,3928],{},[1005,3893,3894,3896,3898,3900,3902],{},[1020,3895,3101],{},[1020,3897,988],{},[1020,3899,988],{},[1020,3901],{},[1020,3903],{},[1005,3905,3906,3908,3910,3912,3914],{},[1020,3907,3089],{},[1020,3909,988],{},[1020,3911],{},[1020,3913],{},[1020,3915],{},[1005,3917,3918,3920,3922,3924,3926],{},[1020,3919,3092],{},[1020,3921],{},[1020,3923,988],{},[1020,3925,1658],{},[1020,3927,1658],{},[1005,3929,3930,3932,3934,3936,3938],{},[1020,3931,3086],{},[1020,3933],{},[1020,3935],{},[1020,3937],{},[1020,3939],{},[554,3941,3942],{},"Сможете ли вы определить формулу для этой таблицы?\nСамая длинная общая подпоследовательность имеет много общего с самой длинной общей подстрокой, и их формулы тоже очень похожи.\nПопробуйте решить задачу самостоятельно.",[574,3944,3946],{"id":3945},"решение-самая-длинная-общая-подпоследовательность","Решение: самая длинная общая подпоследовательность",[554,3948,3949],{},"Формула для заполнения каждой ячейки(для соседелй наверху слева):",[1143,3951,3952,3955],{},[1063,3953,3954],{},"Если буквы не совпадают, выбрать большее значение;",[1063,3956,3957],{},"Если буквы совпадают, значение равно значению ячейки наверху слева +1 (как и в случае с самой длинной общей подстрокой).",[554,3959,3960],{},"Окончательные версии таблиц:",[999,3962,3963,3977],{},[1002,3964,3965],{},[1005,3966,3967,3969,3971,3973,3975],{},[1008,3968,1653],{},[1008,3970,3101],{},[1008,3972,3885],{},[1008,3974,3092],{},[1008,3976,3086],{},[1015,3978,3979,3991,4003,4015],{},[1005,3980,3981,3983,3985,3987,3989],{},[1020,3982,3101],{},[1020,3984,988],{},[1020,3986,988],{},[1020,3988,988],{},[1020,3990,988],{},[1005,3992,3993,3995,3997,3999,4001],{},[1020,3994,3089],{},[1020,3996,988],{},[1020,3998,988],{},[1020,4000,988],{},[1020,4002,988],{},[1005,4004,4005,4007,4009,4011,4013],{},[1020,4006,3092],{},[1020,4008,988],{},[1020,4010,988],{},[1020,4012,1658],{},[1020,4014,1658],{},[1005,4016,4017,4019,4021,4023,4025],{},[1020,4018,3086],{},[1020,4020,988],{},[1020,4022,988],{},[1020,4024,1658],{},[1020,4026,1055],{},[999,4028,4029,4043],{},[1002,4030,4031],{},[1005,4032,4033,4035,4037,4039,4041],{},[1008,4034,1653],{},[1008,4036,3101],{},[1008,4038,3885],{},[1008,4040,3092],{},[1008,4042,3086],{},[1015,4044,4045,4057,4069,4082],{},[1005,4046,4047,4049,4051,4053,4055],{},[1020,4048,3101],{},[1020,4050,988],{},[1020,4052,988],{},[1020,4054,988],{},[1020,4056,988],{},[1005,4058,4059,4061,4063,4065,4067],{},[1020,4060,3885],{},[1020,4062,988],{},[1020,4064,1658],{},[1020,4066,1658],{},[1020,4068,1658],{},[1005,4070,4071,4074,4076,4078,4080],{},[1020,4072,4073],{},"R",[1020,4075,988],{},[1020,4077,1658],{},[1020,4079,1658],{},[1020,4081,1658],{},[1005,4083,4084,4086,4088,4090,4092],{},[1020,4085,3841],{},[1020,4087,988],{},[1020,4089,1658],{},[1020,4091,1658],{},[1020,4093,1658],{},[554,4095,4096],{},"На Python это решение выглядит так:",[3310,4098,4100],{"className":3312,"code":4099,"language":3314,"meta":982,"style":982},"dp_table_fosh = [\"f\", \"o\", \"s\", \"h\"]\ndp_table_fish = [\"f\", \"i\", \"s\", \"h\"]\ndp_table = [[0 for i in range(len(dp_table_fosh))] for i in range(len(dp_table_fish))]\nfor i in range(0, len(dp_table_fish)):\n    for j in range(0, len(dp_table_fosh)):\n        if dp_table_fosh[j] == dp_table_fish[i]:  # Буквы совпадают\n            dp_table[i][j] = dp_table[i-1][j-1] + 1\n        else:  # Буквы не совпали\n            dp_table[i][j] = max(dp_table[i-1][j], dp_table[i][j-1])\nfor i in dp_table:\n    print(i)\n",[3316,4101,4102,4128,4152,4191,4211,4232,4245,4269,4277,4303,4313],{"__ignoreMap":982},[3319,4103,4104,4107,4109,4111,4113,4115,4118,4120,4122,4124,4126],{"class":3321,"line":3322},[3319,4105,4106],{"class":3325},"dp_table_fosh ",[3319,4108,3330],{"class":3329},[3319,4110,3333],{"class":3325},[3319,4112,3367],{"class":3336},[3319,4114,3340],{"class":3325},[3319,4116,4117],{"class":3336},"\"o\"",[3319,4119,3340],{"class":3325},[3319,4121,3348],{"class":3336},[3319,4123,3340],{"class":3325},[3319,4125,3337],{"class":3336},[3319,4127,3355],{"class":3325},[3319,4129,4130,4132,4134,4136,4138,4140,4142,4144,4146,4148,4150],{"class":3321,"line":1443},[3319,4131,3360],{"class":3325},[3319,4133,3330],{"class":3329},[3319,4135,3333],{"class":3325},[3319,4137,3367],{"class":3336},[3319,4139,3340],{"class":3325},[3319,4141,3343],{"class":3336},[3319,4143,3340],{"class":3325},[3319,4145,3348],{"class":3336},[3319,4147,3340],{"class":3325},[3319,4149,3337],{"class":3336},[3319,4151,3355],{"class":3325},[3319,4153,4154,4156,4158,4160,4162,4164,4166,4168,4170,4172,4174,4177,4179,4181,4183,4185,4187,4189],{"class":3321,"line":1458},[3319,4155,3386],{"class":3325},[3319,4157,3330],{"class":3329},[3319,4159,3391],{"class":3325},[3319,4161,642],{"class":3394},[3319,4163,3397],{"class":3329},[3319,4165,3400],{"class":3325},[3319,4167,3403],{"class":3329},[3319,4169,3406],{"class":3394},[3319,4171,3409],{"class":3325},[3319,4173,3412],{"class":3394},[3319,4175,4176],{"class":3325},"(dp_table_fosh))] ",[3319,4178,3418],{"class":3329},[3319,4180,3400],{"class":3325},[3319,4182,3403],{"class":3329},[3319,4184,3406],{"class":3394},[3319,4186,3409],{"class":3325},[3319,4188,3412],{"class":3394},[3319,4190,3431],{"class":3325},[3319,4192,4193,4195,4197,4199,4201,4203,4205,4207,4209],{"class":3321,"line":1449},[3319,4194,3418],{"class":3329},[3319,4196,3400],{"class":3325},[3319,4198,3403],{"class":3329},[3319,4200,3406],{"class":3394},[3319,4202,3409],{"class":3325},[3319,4204,642],{"class":3394},[3319,4206,3340],{"class":3325},[3319,4208,3412],{"class":3394},[3319,4210,3452],{"class":3325},[3319,4212,4213,4215,4217,4219,4221,4223,4225,4227,4229],{"class":3321,"line":1444},[3319,4214,3457],{"class":3329},[3319,4216,3460],{"class":3325},[3319,4218,3403],{"class":3329},[3319,4220,3406],{"class":3394},[3319,4222,3409],{"class":3325},[3319,4224,642],{"class":3394},[3319,4226,3340],{"class":3325},[3319,4228,3412],{"class":3394},[3319,4230,4231],{"class":3325},"(dp_table_fosh)):\n",[3319,4233,4234,4236,4239,4241,4243],{"class":3321,"line":3478},[3319,4235,3481],{"class":3329},[3319,4237,4238],{"class":3325}," dp_table_fosh[j] ",[3319,4240,3487],{"class":3329},[3319,4242,3490],{"class":3325},[3319,4244,3494],{"class":3493},[3319,4246,4247,4249,4251,4253,4255,4257,4259,4261,4263,4265,4267],{"class":3321,"line":3497},[3319,4248,3500],{"class":3325},[3319,4250,3330],{"class":3329},[3319,4252,3505],{"class":3325},[3319,4254,1653],{"class":3329},[3319,4256,988],{"class":3394},[3319,4258,3512],{"class":3325},[3319,4260,1653],{"class":3329},[3319,4262,988],{"class":3394},[3319,4264,3519],{"class":3325},[3319,4266,3522],{"class":3329},[3319,4268,3525],{"class":3394},[3319,4270,4271,4273,4275],{"class":3321,"line":3528},[3319,4272,3531],{"class":3329},[3319,4274,3534],{"class":3325},[3319,4276,3537],{"class":3493},[3319,4278,4279,4281,4283,4286,4289,4291,4293,4296,4298,4300],{"class":3321,"line":3540},[3319,4280,3500],{"class":3325},[3319,4282,3330],{"class":3329},[3319,4284,4285],{"class":3394}," max",[3319,4287,4288],{"class":3325},"(dp_table[i",[3319,4290,1653],{"class":3329},[3319,4292,988],{"class":3394},[3319,4294,4295],{"class":3325},"][j], dp_table[i][j",[3319,4297,1653],{"class":3329},[3319,4299,988],{"class":3394},[3319,4301,4302],{"class":3325},"])\n",[3319,4304,4305,4307,4309,4311],{"class":3321,"line":3550},[3319,4306,3418],{"class":3329},[3319,4308,3400],{"class":3325},[3319,4310,3403],{"class":3329},[3319,4312,3559],{"class":3325},[3319,4314,4315,4317],{"class":3321,"line":3562},[3319,4316,3565],{"class":3394},[3319,4318,3568],{"class":3325},[3310,4320,4322],{"className":3312,"code":4321,"language":3314,"meta":982,"style":982},"dp_table_fosh = [\"f\", \"o\", \"s\", \"h\"]\ndp_table_fort = [\"f\", \"o\", \"r\", \"t\"]\ndp_table = [[0 for i in range(len(dp_table_fosh))] for i in range(len(dp_table_fort))]\nfor i in range(0, len(dp_table_fort)):\n    for j in range(0, len(dp_table_fosh)):\n        if dp_table_fosh[j] == dp_table_fort[i]:  # Буквы совпадают\n            dp_table[i][j] = dp_table[i-1][j-1] + 1\n        else:  # Буквы не совпали\n            dp_table[i][j] = max(dp_table[i-1][j], dp_table[i][j-1])\nfor i in dp_table:\n    print(i)\n",[3316,4323,4324,4348,4374,4413,4434,4454,4467,4491,4499,4521,4531],{"__ignoreMap":982},[3319,4325,4326,4328,4330,4332,4334,4336,4338,4340,4342,4344,4346],{"class":3321,"line":3322},[3319,4327,4106],{"class":3325},[3319,4329,3330],{"class":3329},[3319,4331,3333],{"class":3325},[3319,4333,3367],{"class":3336},[3319,4335,3340],{"class":3325},[3319,4337,4117],{"class":3336},[3319,4339,3340],{"class":3325},[3319,4341,3348],{"class":3336},[3319,4343,3340],{"class":3325},[3319,4345,3337],{"class":3336},[3319,4347,3355],{"class":3325},[3319,4349,4350,4353,4355,4357,4359,4361,4363,4365,4368,4370,4372],{"class":3321,"line":1443},[3319,4351,4352],{"class":3325},"dp_table_fort ",[3319,4354,3330],{"class":3329},[3319,4356,3333],{"class":3325},[3319,4358,3367],{"class":3336},[3319,4360,3340],{"class":3325},[3319,4362,4117],{"class":3336},[3319,4364,3340],{"class":3325},[3319,4366,4367],{"class":3336},"\"r\"",[3319,4369,3340],{"class":3325},[3319,4371,3625],{"class":3336},[3319,4373,3355],{"class":3325},[3319,4375,4376,4378,4380,4382,4384,4386,4388,4390,4392,4394,4396,4398,4400,4402,4404,4406,4408,4410],{"class":3321,"line":1458},[3319,4377,3386],{"class":3325},[3319,4379,3330],{"class":3329},[3319,4381,3391],{"class":3325},[3319,4383,642],{"class":3394},[3319,4385,3397],{"class":3329},[3319,4387,3400],{"class":3325},[3319,4389,3403],{"class":3329},[3319,4391,3406],{"class":3394},[3319,4393,3409],{"class":3325},[3319,4395,3412],{"class":3394},[3319,4397,4176],{"class":3325},[3319,4399,3418],{"class":3329},[3319,4401,3400],{"class":3325},[3319,4403,3403],{"class":3329},[3319,4405,3406],{"class":3394},[3319,4407,3409],{"class":3325},[3319,4409,3412],{"class":3394},[3319,4411,4412],{"class":3325},"(dp_table_fort))]\n",[3319,4414,4415,4417,4419,4421,4423,4425,4427,4429,4431],{"class":3321,"line":1449},[3319,4416,3418],{"class":3329},[3319,4418,3400],{"class":3325},[3319,4420,3403],{"class":3329},[3319,4422,3406],{"class":3394},[3319,4424,3409],{"class":3325},[3319,4426,642],{"class":3394},[3319,4428,3340],{"class":3325},[3319,4430,3412],{"class":3394},[3319,4432,4433],{"class":3325},"(dp_table_fort)):\n",[3319,4435,4436,4438,4440,4442,4444,4446,4448,4450,4452],{"class":3321,"line":1444},[3319,4437,3457],{"class":3329},[3319,4439,3460],{"class":3325},[3319,4441,3403],{"class":3329},[3319,4443,3406],{"class":3394},[3319,4445,3409],{"class":3325},[3319,4447,642],{"class":3394},[3319,4449,3340],{"class":3325},[3319,4451,3412],{"class":3394},[3319,4453,4231],{"class":3325},[3319,4455,4456,4458,4460,4462,4465],{"class":3321,"line":3478},[3319,4457,3481],{"class":3329},[3319,4459,4238],{"class":3325},[3319,4461,3487],{"class":3329},[3319,4463,4464],{"class":3325}," dp_table_fort[i]:  ",[3319,4466,3494],{"class":3493},[3319,4468,4469,4471,4473,4475,4477,4479,4481,4483,4485,4487,4489],{"class":3321,"line":3497},[3319,4470,3500],{"class":3325},[3319,4472,3330],{"class":3329},[3319,4474,3505],{"class":3325},[3319,4476,1653],{"class":3329},[3319,4478,988],{"class":3394},[3319,4480,3512],{"class":3325},[3319,4482,1653],{"class":3329},[3319,4484,988],{"class":3394},[3319,4486,3519],{"class":3325},[3319,4488,3522],{"class":3329},[3319,4490,3525],{"class":3394},[3319,4492,4493,4495,4497],{"class":3321,"line":3528},[3319,4494,3531],{"class":3329},[3319,4496,3534],{"class":3325},[3319,4498,3537],{"class":3493},[3319,4500,4501,4503,4505,4507,4509,4511,4513,4515,4517,4519],{"class":3321,"line":3540},[3319,4502,3500],{"class":3325},[3319,4504,3330],{"class":3329},[3319,4506,4285],{"class":3394},[3319,4508,4288],{"class":3325},[3319,4510,1653],{"class":3329},[3319,4512,988],{"class":3394},[3319,4514,4295],{"class":3325},[3319,4516,1653],{"class":3329},[3319,4518,988],{"class":3394},[3319,4520,4302],{"class":3325},[3319,4522,4523,4525,4527,4529],{"class":3321,"line":3550},[3319,4524,3418],{"class":3329},[3319,4526,3400],{"class":3325},[3319,4528,3403],{"class":3329},[3319,4530,3559],{"class":3325},[3319,4532,4533,4535],{"class":3321,"line":3562},[3319,4534,3565],{"class":3394},[3319,4536,3568],{"class":3325},[554,4538,4539],{},"Ещё примеры применения динамического программирования:",[1060,4541,4542,4545,4548],{},[1063,4543,4544],{},"Биологи используют самую длинную общую подпоследовательность для выявления сходства в цепях ДНК. По этой метрике можно судить о сходстве двух видов животных, двух заболеваний и т.д. Самая длинная общая подпоследовательность используется для поиска лекарства от рассеянного склероза.",[1063,4546,4547],{},"Вы когда-нибудь пользовались ключом diff (например, в команде git diff)? Этот ключ выводит информацию о различиях между двумя файлами, а для этого он использует динамическое программирование.",[1063,4549,4550],{},"Расстояние Левенштейна оценивает, насколько похожи две строки, а для его вычисления применяется динамическое программирование. Расстояние Левенштейна используется в самых разных областях, от проверки орфографии до выявления отправки пользователем данных, защищенных авторским правом.",[554,4552,4553],{},"Поздравляю — вы справились! Безусловно, это была одна из самых сложных тем в программировании.\nНиже посмотрите и выполните упражнения, чтобы закрепить свои знания по теме.",[551,4555,4556],{},[554,4557,4558,4559],{},"В следующей статье речь идёт про ",[558,4560,4561],{"href":303},"алгоритм k ближайших соседей.",[566,4563],{"id":982},[546,4565],{":isList":4566,"title":1208},"[\"Динамическое программирование применяется при оптимизации некоторой характеристики;\",\"Динамическое программирование работает только в ситуациях, в которых задача может быть разбита на автономные подзадачи;\",\"В каждом решении из области динамического программирования строится таблица;\",\"Значения ячеек таблицы обычно соответствуют оптимизируемой характеристике;\",\"Каждая ячейка представляет подзадачу, поэтому вы должны подумать о том, как разбить задачу на подзадачи;\",\"Не существует единой формулы для вычисления решений методом динамического программирования.\"]",[566,4568],{"id":1118},[984,4570],{":isAnswers":4571,":isList":4572,":startOl":988,"isText":989,"title":990},"[\"Да. Вы сможете положить в рюкзак клавиатуру, смартфон и гитару общей стоимостью 4500.\",\"Возьмите воду, еду и камеру.\",\"Строки таблицы clues(столбцы) и blue(строки): | 0 0 0 0 0 | 0 1 0 0 0 | 0 0 2 0 0 | 0 0 0 3 0 |.\"]","[\"Предположим, к предметам из примера первой задачи(гитара, магнитофон, ноутбук) добавился еще один: клавиатура. Она весит 1 кг и стоит 1000₽. Стоит ли ее брать?\",\"Предположим, что вы собираетесь в турпоход. Емкость вашего рюкзака составляет 6 фунтов, и вы можете взять предметы из следующего списка. У каждого предмета имеется стоимость; чем она выше, тем важнее предмет: вода, 3 кг, 10; книга, 1 кг, 3; еда, 2 кг, 9; куртка, 2 кг, 5; камера, 1 кг, 6. Как выглядит оптимальный набор предметов для похода?\",\"Нарисуйте и заполните таблицу для вычисления самой длинной общей подстроки между строками blue и clues.\"]",[554,4574,4575,4576,4580,4581,4584],{},"Попробуйте сами скопировать и запустить код в окне ниже с интерпретатором Python и повторите примеры из статьи чтобы самим увидеть и понять как всё это работает.\nДля этого в ячейке с кодом нажмите клавиши на клавиатуре ",[4577,4578,4579],"strong",{},"Shift+Enter"," или запустите код через ",[4577,4582,4583],{},"кнопку Run"," по значку ▶.",[4586,4587],"jypiter",{},[1439,4589,1441],{},[1439,4591,4592],{},"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 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 .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);}",{"title":982,"searchDepth":1443,"depth":1444,"links":4594},[4595],{"id":1498,"depth":1443,"text":298,"children":4596},[4597,4600,4605],{"id":1513,"depth":1458,"text":1514,"children":4598},[4599],{"id":1567,"depth":1449,"text":1568},{"id":1635,"depth":1458,"text":298,"children":4601},[4602,4603,4604],{"id":1706,"depth":1444,"text":1537},{"id":1887,"depth":1444,"text":1531},{"id":2065,"depth":1444,"text":1534},{"id":2244,"depth":1458,"text":2245,"children":4606},[4607,4608,4609,4610,4611,4612,4617,4618,4623,4626,4627],{"id":2251,"depth":1444,"text":2252},{"id":2525,"depth":1444,"text":2526},{"id":2532,"depth":1444,"text":2533},{"id":2539,"depth":1444,"text":2540},{"id":2657,"depth":1444,"text":2658},{"id":2664,"depth":1449,"text":2665,"children":4613},[4614,4615,4616],{"id":2912,"depth":1444,"text":2913},{"id":3007,"depth":1444,"text":3008},{"id":3014,"depth":1444,"text":3015},{"id":3021,"depth":1449,"text":3022},{"id":3050,"depth":1449,"text":3051,"children":4619},[4620,4621,4622],{"id":3057,"depth":1444,"text":3058},{"id":3148,"depth":1444,"text":3149},{"id":3224,"depth":1444,"text":3225},{"id":3868,"depth":1449,"text":3869,"children":4624},[4625],{"id":3945,"depth":1444,"text":3946},{"id":982,"depth":1449,"text":982},{"id":1118,"depth":1449,"text":982},"2026-05-07","Метод решения сложных задач, разбиваемых на подзадачи. Примеры задач.","images\u002Fblog\u002Fpython\u002Fst34\u002Fimg.png",{},40,34,{"title":298,"description":4629},"k6A73YsSaTmwC6biV5sBOqRPaSklEo44rd-RHN5UF4g",{"id":4637,"title":294,"author":4638,"body":4640,"date":6019,"description":6020,"extension":1484,"image":6021,"meta":6022,"minRead":5682,"navigation":513,"num":6023,"path":295,"seo":6024,"stem":296,"__hash__":6025},"blog\u002Fblog\u002Fpython\u002Fst33.md",{"name":516,"avatar":4639},{"src":536,"alt":537},{"type":539,"value":4641,"toc":6005},[4642,4645,4648,4657,4661,4664,4733,4736,4747,4750,4753,4755,4758,4769,4772,4775,4779,4782,4786,4789,4797,4808,4813,4817,4820,4828,4831,4897,4900,4904,4907,4975,4978,5121,5124,5141,5145,5151,5198,5205,5278,5282,5285,5296,5299,5307,5312,5316,5339,5348,5354,5369,5379,5746,5749,5976,5979,5987,5989,5992,5998,6000,6002],[542,4643,294],{"id":4644},"жадные-алгоритмы",[546,4646],{":isList":4647,"title":549},"[\"Узнаете о жадной стратегии при решении задач.\",\"Разберётесь как браться за невозможные задачи, не имеющие быстрого алгоритмического решения NP-трудные задачи.\",\"Познакомитесь с приближёнными алгоритмами, которые могут использоваться для быстрого нахождения приближённого решения NP-полных задач.\"]",[551,4649,4650],{},[554,4651,4652,4653,4656],{},"В предыдущей статье был рассмотрен: ",[558,4654,4655],{"href":291},"алгоритм Дейкстры",".\nЗдесь далее текст пойдёт о жадных алгоритмах.",[1125,4658,4660],{"id":4659},"задача-составления-расписания","Задача составления расписания",[554,4662,4663],{},"Предположим, имеется учебный класс, в котором нужно провести как можно больше уроков. У вас есть список уроков:",[999,4665,4666,4679],{},[1002,4667,4668],{},[1005,4669,4670,4673,4676],{},[1008,4671,4672],{},"Предмет",[1008,4674,4675],{},"С",[1008,4677,4678],{},"ДО",[1015,4680,4681,4692,4703,4713,4723],{},[1005,4682,4683,4686,4689],{},[1020,4684,4685],{},"ИЗО",[1020,4687,4688],{},"8:00",[1020,4690,4691],{},"9:00",[1005,4693,4694,4697,4700],{},[1020,4695,4696],{},"English",[1020,4698,4699],{},"8:30",[1020,4701,4702],{},"9:30",[1005,4704,4705,4708,4710],{},[1020,4706,4707],{},"Алгебра",[1020,4709,4691],{},[1020,4711,4712],{},"10:00",[1005,4714,4715,4718,4720],{},[1020,4716,4717],{},"Информатика",[1020,4719,4702],{},[1020,4721,4722],{},"10:30",[1005,4724,4725,4728,4730],{},[1020,4726,4727],{},"Физика",[1020,4729,4712],{},[1020,4731,4732],{},"11:00",[554,4734,4735],{},"Провести все уроки не получится, потому что они перекрывают друг друга по времени.\nТребуется провести в классе как можно больше уроков.\nКак отобрать уроки, чтобы полученный набор оказался самым большим из возможных?\nВот какой составить необходимо алгоритм:",[1143,4737,4738,4741,4744],{},[1063,4739,4740],{},"Выбрать урок, завершающийся раньше всех. Это первый урок, который будет проведён в классе.",[1063,4742,4743],{},"Затем выбирается урок, начинающийся после завершения первого урока. И снова следует выбирать урок, который завершается раньше всех остальных. Он становится вторым уроком в расписании класса.",[1063,4745,4746],{},"Продолжайте действовать по тому же принципу, чтобы получить ответ.",[554,4748,4749],{},"Попробуйте алгоритм на примере таблицы выше. ИЗО заканчивается раньше всех уроков, поэтому выбираем первым уроком.\nДалее нужно найти и выбрать следующий урок, который начинается после 9:00 и завершается раньше остальных.\nАнглийский отпадает, но алгебра подходит. Наконец, информатика пересекается по времени с алгеброй, но физика подходит.\nИтак, задача решена, эти три урока должны проводится в классе: ИЗО, алгебра, физика.",[554,4751,4752],{},"Можно подумать что этот алгоритм удивительно прост. Он слишком очевиден, но в этом и заключается суть жадных алгоритмов!\nОни просты! Жадный алгоритм: на каждом своём шаге выбирает всегда оптимальный вариант.\nВ техническом плане выбирается всегда локально-оптимальное решение.\nКонечно такие алгоритмы сработают не всегда, но с задачей из примера или подобной они справляются легко и интуитивно понятно реализуются!\nРассмотрим далее другой пример.",[1125,4754,1514],{"id":1513},[554,4756,4757],{},"Представьте, что вы богатый покупатель или транжира денежных средств.\nВы зашли в магазин или супермаркет с рюкзаком и перед вами множество товаров, которые вы обязательно хотите немедленно купить.\nОднако, ёмкость вашего рюкзака и ваша грузоподъёмность не бесконечна: примерно рюкзак и соответственно вы сможете понести, допустим, 50 кг(как мешок с цементом)!\nВы также хотите купить максимально дорогие вещи!\nМожно легко представить и противоположную ситуацию — у вас абсолютно нет денег и вы хотите всё украсть и также унести 😁.\nНо задача одна и состоит в том, чтобы подобрать товары максимальной стоимости, которые вы смогли бы унести в своём рюкзаке.\nКакой алгоритм использовать?\nПопробуйте жадный алгоритм:",[1143,4759,4760,4763,4766],{},[1063,4761,4762],{},"Выбрать самый дорогой предмет, который поместиться в рюкзаке.",[1063,4764,4765],{},"Выбрать следующий по стоимости предмет, который поместится в рюкзаке.",[1063,4767,4768],{},"И так далее продолжить до заполнения всего места в рюкзаке.",[554,4770,4771],{},"Вот только, как можно было догадаться, на этот раз такая стратегия не приводит к лучшему решению и соответственно она не работает!\nДопустим вы выбираете самый дорогой товар, например, это музыкальный центр. Вы складываете его в рюкзак и место больше ни для чего не остаётся.\nПусть он стоил 1000000 рублей и это был самый дорогой товар в магазине.\nНо допустим, были также ещё и два товара, стоимостью 750000 и 500000 рублей, которые вдвоём поместились бы в ваш рюкзак.\nНо согласно алгоритму описанному выше вы бы их уже не купили.",[554,4773,4774],{},"Очевидно, жадный алгоритм не всегда выдаёт оптимальное решение всей задачи.\nВпрочем, зачастую результат, даже ошибочный, будет не так уж далёк от истинного ответа.\nИ в некоторых задачах достаточно жадного алгоритма, способного решить задачу достаточно хорошо.\nВ таких областях жадные алгоритмы работают отлично, потому что они просто реализуются, а полученное решение обычно близко к оптимуму.",[984,4776],{":isAnswers":4777,":isList":4778,":startOl":988,"isText":989,"title":990},"[\"Выбираем достопримечательности с наибольшей стоимостью в баллах, которую вы успеете посетить в оставшееся время. Остановитесь, когда таких достопримечательностей не останется. Такая стратегия не будет оптимальной.\",\"Жадная стратегия заключается в том, чтобы выбрать самую большую коробку, помещающуюся в оставшемся пространстве, и повторять это до тех пор, пока ещё можно выбрать хотя бы одну коробку. Такое решение не будет оптимальным.\"]","[\"Вы едите заграницу и у вас есть семь дней на знакомство с достопримечательности. Вы присваиваете каждой достопримечательности стоимость в баллах(насколько вы хотите её увидеть) и оцениваете продолжительность посещения. Как увидеть всё самое важное из всей поездки? Предложите жадную стратегию решения данной задачи. Будет ли решение оптимальным?\",\"Вы работаете в фирме по производству мебели и поставляете её. Коробки с мебелью размещаются в грузовике. Все коробки имеют разный размер, и вы стараетесь наиболее эффективно использовать доступное пространство в коробках. Как выбрать коробки для того, чтобы загрузка имела максимальную эффективность? Предложите жадную стратегию для решения данной задачи. Будет ли полученное решение оптимальным?\"]",[554,4780,4781],{},"Рассмотрим ещё пример, в котором без жадных алгоритмов трудно обойтись.",[1125,4783,4785],{"id":4784},"задача-о-покрытии-множества","Задача о покрытии множества",[554,4787,4788],{},"Вы открываете собственную авторскую программу по радио.\nНужно только решить на каких радиостанциях должна транслироваться ваша программа.\nКаждая трансляция на радио стоит денег, поэтому количество станций нужно свести к минимуму с максимальным качеством вещаний.\nИмеется список станций.\nКаждая станция покрывает определённый набор областей для вещания, эти наборы перекрываются по областям.\nКак найти минимальный набор станций, который покрывал бы все 89 субъектов и областей?\nЗадача довольно сложна. Составим алгоритм:",[1143,4790,4791,4794],{},[1063,4792,4793],{},"Составить список всех возможных подмножеств станций – так называемое степенное множество. В нём содержатся 2^n возможных подмножеств.",[1063,4795,4796],{},"Из этого списка выбирается множество с наименьшим набором станций, покрывающих все 89 субъектов.",[554,4798,4799,4800,4803,4804,4807],{},"Проблема решения данной задачи состоит в том, что вычисление всех возможных подмножеств станций займёт слишком много времени.\nДля ",[1095,4801,4802],{},"n"," станций оно потребует времени ",[1095,4805,4806],{},"O(2^n)."," Если станций немного, скажем от 5 до 10, — это допустимо.\nНо подумайте, что произойдёт во всех рассмотренных примерах при большом количестве элементов.\nПредположим, вы можете вычислять по 10 подмножеств в секунду.",[554,4809,4810],{},[1095,4811,4812],{},"Не существует алгоритма, который будет вычислять подмножества с приемлемой скоростью! Что делать? На помощь приходят жадные алгоритмы.",[566,4814,4816],{"id":4815},"приближённые-алгоритмы-реализация","Приближённые алгоритмы: реализация",[554,4818,4819],{},"Вот как выглядит жадный алгоритм, который выдаёт результат, достаточно близкий к оптимальному решению:",[1143,4821,4822,4825],{},[1063,4823,4824],{},"Выбрать станцию, покрывающую наибольшее количество областей, ещё не входящих в покрытие. Если станция будет покрывать некоторые области, уже входящие в покрытие, это нормально.",[1063,4826,4827],{},"Повторять, пока останутся области, не входящие в покрытие.",[554,4829,4830],{},"Этот алгоритм является приближённым. Когда вычисление точного решения занимает слишком много времени, применяется приближённый алгоритм.\nЭффективность приближённого алгоритма оценивается по: быстроте, близости полученного решения к оптимальному.",[554,4832,4833,4834,4893,4894,4896],{},"Жадные алгоритмы хороши не только тем, что они обычно легко формулируются, но и тем, что простота обычно оборачивается скоростью выполнения.\nВ данном случае жадный алгоритм выполняется за время ",[582,4835,4837],{"className":4836,"jax":586},[585],[588,4838,4842,4858],{"style":1577,"xmlns":591,"width":4839,"height":4840,"role":594,"focusable":595,"viewBox":4841,"xmlnsXLink":597},"6.461ex","2.452ex","0 -833.9 2855.6 1083.9",[599,4843,4844,4846,4848,4850,4852,4854],{},[602,4845],{"id":1585,"d":1586},[602,4847],{"id":608,"d":609},[602,4849],{"id":1593,"d":829},[602,4851],{"id":624,"d":625},[602,4853],{"id":628,"d":629},[602,4855],{"id":4856,"d":4857},"MJX-1-TEX-N-2C","M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z",[639,4859,4860],{"stroke":641,"fill":641,"stroke-width":642,"transform":643},[639,4861,4862,4866,4870,4881,4886],{"dataMmlNode":646},[639,4863,4864],{"dataMmlNode":674},[664,4865],{"dataC":1604,"xLinkHref":1605},[639,4867,4868],{"dataMmlNode":662,"transform":1608},[664,4869],{"dataC":666,"xLinkHref":667},[639,4871,4872,4876],{"dataMmlNode":655,"transform":1613},[639,4873,4874],{"dataMmlNode":674},[664,4875],{"dataC":927,"xLinkHref":1623},[639,4877,4879],{"dataMmlNode":681,"transform":4878},"translate(633,363) scale(0.707)",[664,4880],{"dataC":705,"xLinkHref":706},[639,4882,4884],{"dataMmlNode":662,"transform":4883},"translate(2188.6,0)",[664,4885],{"dataC":712,"xLinkHref":713},[639,4887,4889],{"dataMmlNode":662,"transform":4888},"translate(2577.6,0)",[664,4890],{"dataC":4891,"xLinkHref":4892},"2C","#MJX-1-TEX-N-2C"," где ",[1095,4895,4802],{}," – количество радиостанций.",[554,4898,4899],{},"Теперь разберёмся как задача будет выглядеть в программном коде на Python.",[566,4901,4903],{"id":4902},"подготовительный-код","Подготовительный код",[554,4905,4906],{},"В этом примере для простоты будет использоваться небольшое подмножество областей и станций.\nСначала составим список областей:",[3310,4908,4910],{"className":3312,"code":4909,"language":3314,"meta":982,"style":982},"# Для обозначения субъектов РФ используются коды\n# Переданный массив преобразуется в множество\nstates_needed = set([\"28\", \"29\", \"30\", \"31\", \"32\", \"33\", \"34\", \"35\"])  \n",[3316,4911,4912,4917,4922],{"__ignoreMap":982},[3319,4913,4914],{"class":3321,"line":3322},[3319,4915,4916],{"class":3493},"# Для обозначения субъектов РФ используются коды\n",[3319,4918,4919],{"class":3321,"line":1443},[3319,4920,4921],{"class":3493},"# Переданный массив преобразуется в множество\n",[3319,4923,4924,4927,4929,4932,4935,4938,4940,4943,4945,4948,4950,4953,4955,4958,4960,4963,4965,4968,4970,4973],{"class":3321,"line":1458},[3319,4925,4926],{"class":3325},"states_needed ",[3319,4928,3330],{"class":3329},[3319,4930,4931],{"class":3394}," set",[3319,4933,4934],{"class":3325},"([",[3319,4936,4937],{"class":3336},"\"28\"",[3319,4939,3340],{"class":3325},[3319,4941,4942],{"class":3336},"\"29\"",[3319,4944,3340],{"class":3325},[3319,4946,4947],{"class":3336},"\"30\"",[3319,4949,3340],{"class":3325},[3319,4951,4952],{"class":3336},"\"31\"",[3319,4954,3340],{"class":3325},[3319,4956,4957],{"class":3336},"\"32\"",[3319,4959,3340],{"class":3325},[3319,4961,4962],{"class":3336},"\"33\"",[3319,4964,3340],{"class":3325},[3319,4966,4967],{"class":3336},"\"34\"",[3319,4969,3340],{"class":3325},[3319,4971,4972],{"class":3336},"\"35\"",[3319,4974,4302],{"class":3325},[554,4976,4977],{},"В этой реализации используем множество.\nЭта структура данных похожа на список, но каждый элемент может встречаться во множестве не более одного раза.\nМножества не содержат дубликатов. Также понадобится список станций, из которого будет выбираться покрытие.\nВоспользуемся словарём:",[3310,4979,4981],{"className":3312,"code":4980,"language":3314,"meta":982,"style":982},"stations = {}\nstations[\"one\"] = set([\"31\", \"32\", \"33\"])\nstations[\"two\"] = set([\"29\", \"31\", \"28\"])\nstations[\"three\"] = set([\"30\", \"32\", \"34\"])\nstations[\"four\"] = set([\"32\", \"33\"])\nstations[\"five\"] = set([\"34\", \"35\"])\n",[3316,4982,4983,4993,5021,5048,5075,5098],{"__ignoreMap":982},[3319,4984,4985,4988,4990],{"class":3321,"line":3322},[3319,4986,4987],{"class":3325},"stations ",[3319,4989,3330],{"class":3329},[3319,4991,4992],{"class":3325}," {}\n",[3319,4994,4995,4998,5001,5003,5005,5007,5009,5011,5013,5015,5017,5019],{"class":3321,"line":1443},[3319,4996,4997],{"class":3325},"stations[",[3319,4999,5000],{"class":3336},"\"one\"",[3319,5002,3519],{"class":3325},[3319,5004,3330],{"class":3329},[3319,5006,4931],{"class":3394},[3319,5008,4934],{"class":3325},[3319,5010,4952],{"class":3336},[3319,5012,3340],{"class":3325},[3319,5014,4957],{"class":3336},[3319,5016,3340],{"class":3325},[3319,5018,4962],{"class":3336},[3319,5020,4302],{"class":3325},[3319,5022,5023,5025,5028,5030,5032,5034,5036,5038,5040,5042,5044,5046],{"class":3321,"line":1458},[3319,5024,4997],{"class":3325},[3319,5026,5027],{"class":3336},"\"two\"",[3319,5029,3519],{"class":3325},[3319,5031,3330],{"class":3329},[3319,5033,4931],{"class":3394},[3319,5035,4934],{"class":3325},[3319,5037,4942],{"class":3336},[3319,5039,3340],{"class":3325},[3319,5041,4952],{"class":3336},[3319,5043,3340],{"class":3325},[3319,5045,4937],{"class":3336},[3319,5047,4302],{"class":3325},[3319,5049,5050,5052,5055,5057,5059,5061,5063,5065,5067,5069,5071,5073],{"class":3321,"line":1449},[3319,5051,4997],{"class":3325},[3319,5053,5054],{"class":3336},"\"three\"",[3319,5056,3519],{"class":3325},[3319,5058,3330],{"class":3329},[3319,5060,4931],{"class":3394},[3319,5062,4934],{"class":3325},[3319,5064,4947],{"class":3336},[3319,5066,3340],{"class":3325},[3319,5068,4957],{"class":3336},[3319,5070,3340],{"class":3325},[3319,5072,4967],{"class":3336},[3319,5074,4302],{"class":3325},[3319,5076,5077,5079,5082,5084,5086,5088,5090,5092,5094,5096],{"class":3321,"line":1444},[3319,5078,4997],{"class":3325},[3319,5080,5081],{"class":3336},"\"four\"",[3319,5083,3519],{"class":3325},[3319,5085,3330],{"class":3329},[3319,5087,4931],{"class":3394},[3319,5089,4934],{"class":3325},[3319,5091,4957],{"class":3336},[3319,5093,3340],{"class":3325},[3319,5095,4962],{"class":3336},[3319,5097,4302],{"class":3325},[3319,5099,5100,5102,5105,5107,5109,5111,5113,5115,5117,5119],{"class":3321,"line":3478},[3319,5101,4997],{"class":3325},[3319,5103,5104],{"class":3336},"\"five\"",[3319,5106,3519],{"class":3325},[3319,5108,3330],{"class":3329},[3319,5110,4931],{"class":3394},[3319,5112,4934],{"class":3325},[3319,5114,4967],{"class":3336},[3319,5116,3340],{"class":3325},[3319,5118,4972],{"class":3336},[3319,5120,4302],{"class":3325},[554,5122,5123],{},"Ключи — названия станций, а значения — сокращенные обозначения областей, входящих в зону охвата.\nТаким образом, в данном примере станция one вещает в субъектах с кодами 31, 32, 33(Белгородская, Брянская и Владимирская области).\nВсе значения являются множествами. Хранение данных во множествах упрощает работу.\nНаконец, нам понадобится структура данных для хранения итогового набора станций:",[3310,5125,5127],{"className":3312,"code":5126,"language":3314,"meta":982,"style":982},"final_stations = set()\n",[3316,5128,5129],{"__ignoreMap":982},[3319,5130,5131,5134,5136,5138],{"class":3321,"line":3322},[3319,5132,5133],{"class":3325},"final_stations ",[3319,5135,3330],{"class":3329},[3319,5137,4931],{"class":3394},[3319,5139,5140],{"class":3325},"()\n",[566,5142,5144],{"id":5143},"вычисление-ответа","Вычисление ответа",[554,5146,5147,5148,1397],{},"Теперь необходимо вычислить набор используемых станций. Правильных решений может быть несколько.\nНеобходимо перебрать все станции и выбрать ту, которая обслуживает больше всего субъектов-областей, не входящих в текущее покрытие.\nБудем называть её ",[3316,5149,5150],{},"best_station",[3310,5152,5154],{"className":3312,"code":5153,"language":3314,"meta":982,"style":982},"while states_needed:\n  best_station = None\n  states_covered = set()\n  for station, states_for_station in stations.items():\n",[3316,5155,5156,5164,5174,5185],{"__ignoreMap":982},[3319,5157,5158,5161],{"class":3321,"line":3322},[3319,5159,5160],{"class":3329},"while",[3319,5162,5163],{"class":3325}," states_needed:\n",[3319,5165,5166,5169,5171],{"class":3321,"line":1443},[3319,5167,5168],{"class":3325},"  best_station ",[3319,5170,3330],{"class":3329},[3319,5172,5173],{"class":3394}," None\n",[3319,5175,5176,5179,5181,5183],{"class":3321,"line":1458},[3319,5177,5178],{"class":3325},"  states_covered ",[3319,5180,3330],{"class":3329},[3319,5182,4931],{"class":3394},[3319,5184,5140],{"class":3325},[3319,5186,5187,5190,5193,5195],{"class":3321,"line":1449},[3319,5188,5189],{"class":3329},"  for",[3319,5191,5192],{"class":3325}," station, states_for_station ",[3319,5194,3403],{"class":3329},[3319,5196,5197],{"class":3325}," stations.items():\n",[554,5199,5200,5201,5204],{},"Множество ",[3316,5202,5203],{},"states_covered содержит"," все области, обслуживаемые этой станцией, которые ещё не входят в текущее покрытие.\nПомните, мы ищем станцию, которая будет обслуживать большинство ещё не охваченных областей.\nЦикл for перебирает все станции и находит среди них наилучшую.\nРассмотрим тело цикла for:",[3310,5206,5208],{"className":3312,"code":5207,"language":3314,"meta":982,"style":982},"for station, states_for_station in stations.items():\n  covered = states_needed & states_for_station # Пересечение множеств\n  if len(covered) > len(states_covered):\n    best_station = station\n    states_covered = covered\n",[3316,5209,5210,5220,5239,5258,5268],{"__ignoreMap":982},[3319,5211,5212,5214,5216,5218],{"class":3321,"line":3322},[3319,5213,3418],{"class":3329},[3319,5215,5192],{"class":3325},[3319,5217,3403],{"class":3329},[3319,5219,5197],{"class":3325},[3319,5221,5222,5225,5227,5230,5233,5236],{"class":3321,"line":1443},[3319,5223,5224],{"class":3325},"  covered ",[3319,5226,3330],{"class":3329},[3319,5228,5229],{"class":3325}," states_needed ",[3319,5231,5232],{"class":3329},"&",[3319,5234,5235],{"class":3325}," states_for_station ",[3319,5237,5238],{"class":3493},"# Пересечение множеств\n",[3319,5240,5241,5244,5247,5250,5253,5255],{"class":3321,"line":1458},[3319,5242,5243],{"class":3329},"  if",[3319,5245,5246],{"class":3394}," len",[3319,5248,5249],{"class":3325},"(covered) ",[3319,5251,5252],{"class":3329},">",[3319,5254,5246],{"class":3394},[3319,5256,5257],{"class":3325},"(states_covered):\n",[3319,5259,5260,5263,5265],{"class":3321,"line":1449},[3319,5261,5262],{"class":3325},"    best_station ",[3319,5264,3330],{"class":3329},[3319,5266,5267],{"class":3325}," station\n",[3319,5269,5270,5273,5275],{"class":3321,"line":1444},[3319,5271,5272],{"class":3325},"    states_covered ",[3319,5274,3330],{"class":3329},[3319,5276,5277],{"class":3325}," covered\n",[566,5279,5281],{"id":5280},"про-множества","Про множества",[554,5283,5284],{},"С двумя множествами можно выполнить ряд операций:",[1060,5286,5287,5290,5293],{},[1063,5288,5289],{},"объединение множеств означает слияние элементов обоих множеств;",[1063,5291,5292],{},"под операцией пересечения множеств понимается поиск элементов, входящих в оба множества;",[1063,5294,5295],{},"под разностью множеств понимается исключение из одного множества элементов, присутствующих в другом множестве.",[554,5297,5298],{},"Основные особенности множеств:",[1060,5300,5301,5304],{},[1063,5302,5303],{},"множества похожи на списки, но не содержат дубликатов;",[1063,5305,5306],{},"с множествами можно выполнять различные операции — объединение пересечение и разность.",[554,5308,5309],{},[558,5310,5311],{"href":231},"Подробнее про множества",[566,5313,5315],{"id":5314},"допишем-код","Допишем код",[554,5317,5200,5318,5321,5322,5325,5326,5329,5330,5332,5333,5335,5336,5338],{},[3316,5319,5320],{},"covered"," содержит области, присутствующие как ",[3316,5323,5324],{},"states_needed",", так и в ",[3316,5327,5328],{},"states_for_station",".\nТаким образом, ",[3316,5331,5320],{}," — множество областей, не входящих в покрытие, которые покрываются текущей станцией!\nЗатем мы проверяем, покрывает ли эта станция больше областей, чем текущая станция ",[3316,5334,5150],{},".\nЕсли условие выполняется, то станция сохраняется в ",[3316,5337,5150],{},".\nНаконец, после завершения цикла best_station добавляется в итоговый список станции:",[3310,5340,5342],{"className":3312,"code":5341,"language":3314,"meta":982,"style":982},"final_station.add(best_station)\n",[3316,5343,5344],{"__ignoreMap":982},[3319,5345,5346],{"class":3321,"line":3322},[3319,5347,5341],{"class":3325},[554,5349,5350,5351,5353],{},"Также необходимо обновить содержимое ",[3316,5352,5324],{},".\nТе области(субъекты), которые входят в зону покрытия станций, больше не нужны:",[3310,5355,5357],{"className":3312,"code":5356,"language":3314,"meta":982,"style":982},"states_needed -= states_covered\n",[3316,5358,5359],{"__ignoreMap":982},[3319,5360,5361,5363,5366],{"class":3321,"line":3322},[3319,5362,4926],{"class":3325},[3319,5364,5365],{"class":3329},"-=",[3319,5367,5368],{"class":3325}," states_covered\n",[554,5370,5371,5372,5374,5375,5378],{},"Цикл продолжается, пока множество ",[3316,5373,5324],{}," не станет пустым. В конце остаюётся только вывести ",[3316,5376,5377],{},"final_stations",".\nПолный код выглядит так:",[3310,5380,5382],{"className":3312,"code":5381,"language":3314,"meta":982,"style":982},"# Для обозначения субъектов РФ используются коды\n# Переданный массив преобразуется в множество\nstates_needed = set([\"28\", \"29\", \"30\", \"31\", \"32\", \"33\", \"34\", \"35\"]) \n\nstations = {}\nstations[\"one\"] = set([\"31\", \"32\", \"33\"])\nstations[\"two\"] = set([\"29\", \"31\", \"28\"])\nstations[\"three\"] = set([\"30\", \"32\", \"34\"])\nstations[\"four\"] = set([\"32\", \"33\"])\nstations[\"five\"] = set([\"34\", \"35\"])\n\nfinal_stations = set()\nwhile states_needed:\n  best_station = None\n  states_covered = set()\n  for station, states_for_station in stations.items():\n    covered = states_needed & states_for_station\n    if len(covered) > len(states_covered) and station not in final_stations:\n      best_station = station\n      states_covered = covered\n  if best_station is not None:\n    states_needed -= states_covered\n    final_stations.add(best_station)\n    stations.pop(best_station)\n    \nprint(final_stations)\n",[3316,5383,5384,5388,5392,5435,5440,5448,5474,5500,5526,5548,5570,5574,5585,5592,5601,5612,5623,5638,5670,5680,5690,5709,5719,5725,5731,5737],{"__ignoreMap":982},[3319,5385,5386],{"class":3321,"line":3322},[3319,5387,4916],{"class":3493},[3319,5389,5390],{"class":3321,"line":1443},[3319,5391,4921],{"class":3493},[3319,5393,5394,5396,5398,5400,5402,5404,5406,5408,5410,5412,5414,5416,5418,5420,5422,5424,5426,5428,5430,5432],{"class":3321,"line":1458},[3319,5395,4926],{"class":3325},[3319,5397,3330],{"class":3329},[3319,5399,4931],{"class":3394},[3319,5401,4934],{"class":3325},[3319,5403,4937],{"class":3336},[3319,5405,3340],{"class":3325},[3319,5407,4942],{"class":3336},[3319,5409,3340],{"class":3325},[3319,5411,4947],{"class":3336},[3319,5413,3340],{"class":3325},[3319,5415,4952],{"class":3336},[3319,5417,3340],{"class":3325},[3319,5419,4957],{"class":3336},[3319,5421,3340],{"class":3325},[3319,5423,4962],{"class":3336},[3319,5425,3340],{"class":3325},[3319,5427,4967],{"class":3336},[3319,5429,3340],{"class":3325},[3319,5431,4972],{"class":3336},[3319,5433,5434],{"class":3325},"]) \n",[3319,5436,5437],{"class":3321,"line":1449},[3319,5438,5439],{"emptyLinePlaceholder":513},"\n",[3319,5441,5442,5444,5446],{"class":3321,"line":1444},[3319,5443,4987],{"class":3325},[3319,5445,3330],{"class":3329},[3319,5447,4992],{"class":3325},[3319,5449,5450,5452,5454,5456,5458,5460,5462,5464,5466,5468,5470,5472],{"class":3321,"line":3478},[3319,5451,4997],{"class":3325},[3319,5453,5000],{"class":3336},[3319,5455,3519],{"class":3325},[3319,5457,3330],{"class":3329},[3319,5459,4931],{"class":3394},[3319,5461,4934],{"class":3325},[3319,5463,4952],{"class":3336},[3319,5465,3340],{"class":3325},[3319,5467,4957],{"class":3336},[3319,5469,3340],{"class":3325},[3319,5471,4962],{"class":3336},[3319,5473,4302],{"class":3325},[3319,5475,5476,5478,5480,5482,5484,5486,5488,5490,5492,5494,5496,5498],{"class":3321,"line":3497},[3319,5477,4997],{"class":3325},[3319,5479,5027],{"class":3336},[3319,5481,3519],{"class":3325},[3319,5483,3330],{"class":3329},[3319,5485,4931],{"class":3394},[3319,5487,4934],{"class":3325},[3319,5489,4942],{"class":3336},[3319,5491,3340],{"class":3325},[3319,5493,4952],{"class":3336},[3319,5495,3340],{"class":3325},[3319,5497,4937],{"class":3336},[3319,5499,4302],{"class":3325},[3319,5501,5502,5504,5506,5508,5510,5512,5514,5516,5518,5520,5522,5524],{"class":3321,"line":3528},[3319,5503,4997],{"class":3325},[3319,5505,5054],{"class":3336},[3319,5507,3519],{"class":3325},[3319,5509,3330],{"class":3329},[3319,5511,4931],{"class":3394},[3319,5513,4934],{"class":3325},[3319,5515,4947],{"class":3336},[3319,5517,3340],{"class":3325},[3319,5519,4957],{"class":3336},[3319,5521,3340],{"class":3325},[3319,5523,4967],{"class":3336},[3319,5525,4302],{"class":3325},[3319,5527,5528,5530,5532,5534,5536,5538,5540,5542,5544,5546],{"class":3321,"line":3540},[3319,5529,4997],{"class":3325},[3319,5531,5081],{"class":3336},[3319,5533,3519],{"class":3325},[3319,5535,3330],{"class":3329},[3319,5537,4931],{"class":3394},[3319,5539,4934],{"class":3325},[3319,5541,4957],{"class":3336},[3319,5543,3340],{"class":3325},[3319,5545,4962],{"class":3336},[3319,5547,4302],{"class":3325},[3319,5549,5550,5552,5554,5556,5558,5560,5562,5564,5566,5568],{"class":3321,"line":3550},[3319,5551,4997],{"class":3325},[3319,5553,5104],{"class":3336},[3319,5555,3519],{"class":3325},[3319,5557,3330],{"class":3329},[3319,5559,4931],{"class":3394},[3319,5561,4934],{"class":3325},[3319,5563,4967],{"class":3336},[3319,5565,3340],{"class":3325},[3319,5567,4972],{"class":3336},[3319,5569,4302],{"class":3325},[3319,5571,5572],{"class":3321,"line":3562},[3319,5573,5439],{"emptyLinePlaceholder":513},[3319,5575,5577,5579,5581,5583],{"class":3321,"line":5576},12,[3319,5578,5133],{"class":3325},[3319,5580,3330],{"class":3329},[3319,5582,4931],{"class":3394},[3319,5584,5140],{"class":3325},[3319,5586,5588,5590],{"class":3321,"line":5587},13,[3319,5589,5160],{"class":3329},[3319,5591,5163],{"class":3325},[3319,5593,5595,5597,5599],{"class":3321,"line":5594},14,[3319,5596,5168],{"class":3325},[3319,5598,3330],{"class":3329},[3319,5600,5173],{"class":3394},[3319,5602,5604,5606,5608,5610],{"class":3321,"line":5603},15,[3319,5605,5178],{"class":3325},[3319,5607,3330],{"class":3329},[3319,5609,4931],{"class":3394},[3319,5611,5140],{"class":3325},[3319,5613,5615,5617,5619,5621],{"class":3321,"line":5614},16,[3319,5616,5189],{"class":3329},[3319,5618,5192],{"class":3325},[3319,5620,3403],{"class":3329},[3319,5622,5197],{"class":3325},[3319,5624,5626,5629,5631,5633,5635],{"class":3321,"line":5625},17,[3319,5627,5628],{"class":3325},"    covered ",[3319,5630,3330],{"class":3329},[3319,5632,5229],{"class":3325},[3319,5634,5232],{"class":3329},[3319,5636,5637],{"class":3325}," states_for_station\n",[3319,5639,5641,5644,5646,5648,5650,5652,5655,5658,5661,5664,5667],{"class":3321,"line":5640},18,[3319,5642,5643],{"class":3329},"    if",[3319,5645,5246],{"class":3394},[3319,5647,5249],{"class":3325},[3319,5649,5252],{"class":3329},[3319,5651,5246],{"class":3394},[3319,5653,5654],{"class":3325},"(states_covered) ",[3319,5656,5657],{"class":3329},"and",[3319,5659,5660],{"class":3325}," station ",[3319,5662,5663],{"class":3329},"not",[3319,5665,5666],{"class":3329}," in",[3319,5668,5669],{"class":3325}," final_stations:\n",[3319,5671,5673,5676,5678],{"class":3321,"line":5672},19,[3319,5674,5675],{"class":3325},"      best_station ",[3319,5677,3330],{"class":3329},[3319,5679,5267],{"class":3325},[3319,5681,5683,5686,5688],{"class":3321,"line":5682},20,[3319,5684,5685],{"class":3325},"      states_covered ",[3319,5687,3330],{"class":3329},[3319,5689,5277],{"class":3325},[3319,5691,5693,5695,5698,5701,5704,5707],{"class":3321,"line":5692},21,[3319,5694,5243],{"class":3329},[3319,5696,5697],{"class":3325}," best_station ",[3319,5699,5700],{"class":3329},"is",[3319,5702,5703],{"class":3329}," not",[3319,5705,5706],{"class":3394}," None",[3319,5708,3754],{"class":3325},[3319,5710,5712,5715,5717],{"class":3321,"line":5711},22,[3319,5713,5714],{"class":3325},"    states_needed ",[3319,5716,5365],{"class":3329},[3319,5718,5368],{"class":3325},[3319,5720,5722],{"class":3321,"line":5721},23,[3319,5723,5724],{"class":3325},"    final_stations.add(best_station)\n",[3319,5726,5728],{"class":3321,"line":5727},24,[3319,5729,5730],{"class":3325},"    stations.pop(best_station)\n",[3319,5732,5734],{"class":3321,"line":5733},25,[3319,5735,5736],{"class":3325},"    \n",[3319,5738,5740,5743],{"class":3321,"line":5739},26,[3319,5741,5742],{"class":3394},"print",[3319,5744,5745],{"class":3325},"(final_stations)\n",[554,5747,5748],{},"Вместо станций 1,2,3,5 можно было выбрать станции 2,3,4, и 5.\nНиже сравним время выполнения алгоритма:",[999,5750,5751,5864],{},[1002,5752,5753],{},[1005,5754,5755,5758,5806],{},[1008,5756,5757],{},"Кол-во станций",[1008,5759,5760,5761],{},"Точный алгоритм ",[582,5762,5764],{"className":5763,"jax":586},[585],[588,5765,5766,5779],{"style":1577,"xmlns":591,"width":1578,"height":1579,"role":594,"focusable":595,"viewBox":1580,"xmlnsXLink":597},[599,5767,5768,5771,5773,5775,5777],{},[602,5769],{"id":5770,"d":1586},"MJX-2-TEX-I-1D442",[602,5772],{"id":803,"d":609},[602,5774],{"id":815,"d":625},[602,5776],{"id":828,"d":829},[602,5778],{"id":818,"d":629},[639,5780,5781],{"stroke":641,"fill":641,"stroke-width":642,"transform":643},[639,5782,5783,5788,5792,5802],{"dataMmlNode":646},[639,5784,5785],{"dataMmlNode":674},[664,5786],{"dataC":1604,"xLinkHref":5787},"#MJX-2-TEX-I-1D442",[639,5789,5790],{"dataMmlNode":662,"transform":1608},[664,5791],{"dataC":666,"xLinkHref":846},[639,5793,5794,5798],{"dataMmlNode":655,"transform":1613},[639,5795,5796],{"dataMmlNode":681},[664,5797],{"dataC":705,"xLinkHref":874},[639,5799,5800],{"dataMmlNode":674,"transform":1620},[664,5801],{"dataC":927,"xLinkHref":928},[639,5803,5804],{"dataMmlNode":662,"transform":1626},[664,5805],{"dataC":712,"xLinkHref":879},[1008,5807,5808,5809],{},"Жадный алгоритм ",[582,5810,5812],{"className":5811,"jax":586},[585],[588,5813,5816,5833],{"style":1577,"xmlns":591,"width":5814,"height":4840,"role":594,"focusable":595,"viewBox":5815,"xmlnsXLink":597},"5.832ex","0 -833.9 2577.6 1083.9",[599,5817,5818,5821,5824,5827,5830],{},[602,5819],{"id":5820,"d":1586},"MJX-3-TEX-I-1D442",[602,5822],{"id":5823,"d":609},"MJX-3-TEX-N-28",[602,5825],{"id":5826,"d":829},"MJX-3-TEX-I-1D45B",[602,5828],{"id":5829,"d":625},"MJX-3-TEX-N-32",[602,5831],{"id":5832,"d":629},"MJX-3-TEX-N-29",[639,5834,5835],{"stroke":641,"fill":641,"stroke-width":642,"transform":643},[639,5836,5837,5842,5847,5859],{"dataMmlNode":646},[639,5838,5839],{"dataMmlNode":674},[664,5840],{"dataC":1604,"xLinkHref":5841},"#MJX-3-TEX-I-1D442",[639,5843,5844],{"dataMmlNode":662,"transform":1608},[664,5845],{"dataC":666,"xLinkHref":5846},"#MJX-3-TEX-N-28",[639,5848,5849,5854],{"dataMmlNode":655,"transform":1613},[639,5850,5851],{"dataMmlNode":674},[664,5852],{"dataC":927,"xLinkHref":5853},"#MJX-3-TEX-I-1D45B",[639,5855,5856],{"dataMmlNode":681,"transform":4878},[664,5857],{"dataC":705,"xLinkHref":5858},"#MJX-3-TEX-N-32",[639,5860,5861],{"dataMmlNode":662,"transform":4883},[664,5862],{"dataC":712,"xLinkHref":5863},"#MJX-3-TEX-N-29",[1015,5865,5866,5876,5887,5896],{},[1005,5867,5868,5870,5873],{},[1020,5869,1033],{},[1020,5871,5872],{},"3.3 сек",[1020,5874,5875],{},"2.5 сек",[1005,5877,5878,5881,5884],{},[1020,5879,5880],{},"10",[1020,5882,5883],{},"102.5 сек",[1020,5885,5886],{},"10 сек",[1005,5888,5889,5891,5894],{},[1020,5890,705],{},[1020,5892,5893],{},"13.6 лет",[1020,5895,5883],{},[1005,5897,5898,5901,5973],{},[1020,5899,5900],{},"100",[1020,5902,5903,5972],{},[582,5904,5906],{"className":5905,"jax":586},[585],[588,5907,5912,5932],{"style":5908,"xmlns":591,"width":5909,"height":5910,"role":594,"focusable":595,"viewBox":5911,"xmlnsXLink":597},"vertical-align: -0.05ex;","7.318ex","2.005ex","0 -864 3234.6 886",[599,5913,5914,5918,5922,5925,5929],{},[602,5915],{"id":5916,"d":5917},"MJX-4-TEX-N-34","M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z",[602,5919],{"id":5920,"d":5921},"MJX-4-TEX-N-2217","M229 286Q216 420 216 436Q216 454 240 464Q241 464 245 464T251 465Q263 464 273 456T283 436Q283 419 277 356T270 286L328 328Q384 369 389 372T399 375Q412 375 423 365T435 338Q435 325 425 315Q420 312 357 282T289 250L355 219L425 184Q434 175 434 161Q434 146 425 136T401 125Q393 125 383 131T328 171L270 213Q283 79 283 63Q283 53 276 44T250 35Q231 35 224 44T216 63Q216 80 222 143T229 213L171 171Q115 130 110 127Q106 124 100 124Q87 124 76 134T64 161Q64 166 64 169T67 175T72 181T81 188T94 195T113 204T138 215T170 230T210 250L74 315Q65 324 65 338Q65 353 74 363T98 374Q106 374 116 368T171 328L229 286Z",[602,5923],{"id":5924,"d":617},"MJX-4-TEX-N-31",[602,5926],{"id":5927,"d":5928},"MJX-4-TEX-N-30","M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z",[602,5930],{"id":5931,"d":625},"MJX-4-TEX-N-32",[639,5933,5934],{"stroke":641,"fill":641,"stroke-width":642,"transform":643},[639,5935,5936,5942,5949],{"dataMmlNode":646},[639,5937,5938],{"dataMmlNode":681},[664,5939],{"dataC":5940,"xLinkHref":5941},"34","#MJX-4-TEX-N-34",[639,5943,5945],{"dataMmlNode":662,"transform":5944},"translate(722.2,0)",[664,5946],{"dataC":5947,"xLinkHref":5948},"2217","#MJX-4-TEX-N-2217",[639,5950,5952,5962],{"dataMmlNode":655,"transform":5951},"translate(1444.4,0)",[639,5953,5954,5957],{"dataMmlNode":681},[664,5955],{"dataC":685,"xLinkHref":5956},"#MJX-4-TEX-N-31",[664,5958],{"dataC":5959,"xLinkHref":5960,"transform":5961},"30","#MJX-4-TEX-N-30","translate(500,0)",[639,5963,5965],{"dataMmlNode":658,"transform":5964,"dataMjxTexclass":659},"translate(1033,393.1) scale(0.707)",[639,5966,5967,5970],{"dataMmlNode":681},[664,5968],{"dataC":705,"xLinkHref":5969},"#MJX-4-TEX-N-32",[664,5971],{"dataC":685,"xLinkHref":5956,"transform":5961}," лет",[1020,5974,5975],{},"16.68 мин",[554,5977,5978],{},"Жадные алгоритмы не всегда дают точный ответ, но они очень быстрые.\nЗадача о покрытии множеств относится к NP-трудным задачам.\nНемного позже в статьях я приведу больше примеров об NP-трудных задачах.\nА на этом знакомство с жадными алгоритмами можно считать успешным.",[551,5980,5981],{},[554,5982,5983,5984,5986],{},"В следующей статье речь пойдёт про ",[558,5985,560],{"href":299},".",[566,5988],{"id":982},[546,5990],{":isList":5991,"title":1208},"[\"Жадные алгоритмы стремятся к локальной оптимизации в расчёте на то, что в итоге будет достигнут глобальный оптимум;\",\"Если у вас имеется NP-трудная задача, лучше всего воспользоваться приближённым алгоритмом;\",\"Жадные алгоритмы легко реализовать и быстро выполнить, поэтому из них получаются хорошие приближённые алгоритмы.\"]",[554,5993,4575,5994,4580,5996,4584],{},[4577,5995,4579],{},[4577,5997,4583],{},[4586,5999],{},[1439,6001,1441],{},[1439,6003,6004],{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}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 pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}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);}",{"title":982,"searchDepth":1443,"depth":1444,"links":6006},[6007],{"id":4644,"depth":1443,"text":294,"children":6008},[6009,6010,6011],{"id":4659,"depth":1458,"text":4660},{"id":1513,"depth":1458,"text":1514},{"id":4784,"depth":1458,"text":4785,"children":6012},[6013,6014,6015,6016,6017,6018],{"id":4815,"depth":1449,"text":4816},{"id":4902,"depth":1449,"text":4903},{"id":5143,"depth":1449,"text":5144},{"id":5280,"depth":1449,"text":5281},{"id":5314,"depth":1449,"text":5315},{"id":982,"depth":1449,"text":982},"2026-04-28","Жадная стратегия при решении задач. NP-трудные задачи. Приближенное решение NP-полных задач.","images\u002Fblog\u002Fpython\u002Fst33\u002Fimg.png",{},33,{"title":294,"description":6020},"D4InitWt1v6iVnXaEcZvfWlmvWdgfLKLkICUhcARB_0",{"id":6027,"title":290,"author":6028,"body":6030,"date":7626,"description":7627,"extension":1484,"image":7628,"meta":7629,"minRead":7354,"navigation":513,"num":7402,"path":291,"seo":7630,"stem":292,"__hash__":7631},"blog\u002Fblog\u002Fpython\u002Fst32.md",{"name":516,"avatar":6029},{"src":536,"alt":537},{"type":539,"value":6031,"toc":7615},[6032,6035,6038,6046,6053,6059,6063,6066,6072,6075,6089,6095,6098,6104,6107,6115,6121,6124,6127,6138,6141,6147,6152,6155,6159,6165,6171,6182,6185,6188,6191,6195,6198,6204,6207,6210,6216,6219,6224,6229,6235,6238,6244,6250,6256,6266,6269,6272,6282,6285,6295,6298,6301,6304,6310,6313,6317,6320,6326,6329,6335,6338,6344,6347,6353,6356,6362,6377,6381,6384,6390,6393,6407,6410,6465,6472,6499,6502,6542,6545,6641,6648,6718,6721,6773,6776,6792,6795,6951,6958,7073,7076,7079,7591,7599,7601,7604,7610,7612],[542,6033,290],{"id":6034},"алгоритм-дейкстры",[546,6036],{":isList":6037,"title":549},"[\"Узнаете о взвешенных графах, где рёбрам назначаются большие или меньшие веса.\",\"Изучите алгоритм Дейкстры, который позволяет получить ответ на вопрос: \\\"Как выглядит кратчайший путь к X?\\\" на взвешенных графах.\",\"Узнаете о циклах в графах, для которых алгоритм Дейкстры не работает.\"]",[551,6039,6040],{},[554,6041,6042,6043,6045],{},"В предыдущей статье были рассмотрены сбалансированные деревья: ",[558,6044,286],{"href":287},".\nЗдесь далее текст пойдёт о взвешенных графах и алгоритме Эдсгера Дейкстры.",[554,6047,6048,6049,6052],{},"В статье про ",[558,6050,6051],{"href":275},"поиск в ширину"," можно увидеть, как найти путь из точки А в точку В.\nНайденный путь не обязательно окажется самым быстрым.\nЭтот путь считается кратчайшим только потому что состоит из наименьшего числа сегментов(рёбер).\nНо представим, что с каждым сегментом связывается продолжительность перемещения.\nИ тогда может выясниться, что существует не самый кратчайший, но более быстрый путь.",[554,6054,6055,6056,5986],{},"Алгоритм поиска в ширину находит путь с минимальным количеством сегментов(рёбер у графа).\nА если необходимо найти самый быстрый путь? Быстрее всего его найти при помощи ",[1095,6057,6058],{},"алгоритма Дейкстры",[1125,6060,6062],{"id":6061},"работа-алгоритма-дейкстры","Работа алгоритма Дейкстры",[554,6064,6065],{},"Посмотрим на граф и как алгоритм Дейкстры поработает с таким графом.",[554,6067,6068],{},[594,6069],{"alt":6070,"src":6071},"Пример взвешенного графа","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_1.png",[554,6073,6074],{},"Каждому ребру назначается время перемещения, например, в минутах.\nАлгоритм Дейкстры используется для поиска пути от начальной точки к конечной за кратчайшее возможное время.\nПрименив к этому графу поиск в ширину, вы получите следующий кратчайший путь: начало → А → конец.\nЭтот путь занимает 7 минут.\nА может существовать путь, который займёт меньше времени? Алгоритм Дейкстры состоит из четырёх шагов:",[1143,6076,6077,6080,6083,6086],{},[1063,6078,6079],{},"Найти узел с наименьшей стоимостью (т.е. узел, до которого можно добраться за минимальное время);",[1063,6081,6082],{},"Обновить стоимости соседей этого узла;",[1063,6084,6085],{},"Повторять, пока это не будет сделано для всех узлов графа;",[1063,6087,6088],{},"Вычислить итоговый путь.",[554,6090,6091,6094],{},[1095,6092,6093],{},"Шаг 1:"," найти узел с наименьшей стоимость. В самом начале выбираем, куда направиться: к узлу A или узлу B?\nСколько времени необходимо, чтобы добраться до каждого из этих узлов?",[554,6096,6097],{},"До узла A – 7 минут, а до узла B – 3 минуты. Что касается остальных узлов, о них алгоритм пока ничего не знает.\nТак как время достижения конечного узла остаётся неизвестным, считается, что оно бесконечно.\nУзел B – ближайший, т.к. до него всего 3 минуты.",[554,6099,6100,6103],{},[1095,6101,6102],{},"Шаг 2:"," вычислить, сколько времени потребуется для того, чтобы добраться до всех внешних соседей B при переходе по ребру из B.\nПри этом обнаруживается более короткий путь к узлу A. Ранее до перехода к нему требовалось 7 минут, теперь же 6.",[554,6105,6106],{},"Если находится таким способом, более короткий путь для соседа B, то необходимо обновить его стоимость.\nВ данном случае найдено:",[1060,6108,6109,6112],{},[1063,6110,6111],{},"более короткий путь к A (сокращение с 7 до 6 минут);",[1063,6113,6114],{},"первый путь к конечному узлу до 8 минут.",[554,6116,6117,6120],{},[1095,6118,6119],{},"Шаг 3:"," повторение.",[554,6122,6123],{},"Снова выполняется шаг 1. С узлом B работа закончена, поэтому наименьшая оценка по времени производится по узлу A.",[554,6125,6126],{},"Снова выполняется шаг 2. Обновляем стоимости внешних соседей для узла A.\nАлгоритм вычисляет, что путь до конечного узла теперь занимает 7 минут! Алгоритм на этом завершается.\nК моменту завершения работы алгоритма становится известно:",[1060,6128,6129,6132,6135],{},[1063,6130,6131],{},"Чтобы добраться до узла B, нужно 3 минуты;",[1063,6133,6134],{},"Чтобы добрать до узла A, нужно 6 минут;",[1063,6136,6137],{},"Чтобы добраться до конечного узла, нужно 7 минут.",[554,6139,6140],{},"Последний шаг – вычисление итогового пути(разберёмся с ним ниже). А пока просто посмотрим как выглядит итоговой путь:",[554,6142,6143],{},[594,6144],{"alt":6145,"src":6146},"Пример взвешенного графа: итоговый путь","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_2.png",[551,6148,6149],{},[554,6150,6151],{},"Алгоритм поиска в ширину не найдёт этот путь как кратчайший, потому что он состоит из трёх рёбер, а от начального до конечного можно добраться всего по двум рёбрам графа.",[554,6153,6154],{},"В предыдущей статье было описание использования алгоритма поиска в ширину для нахождения кратчайшего пути на графе между двумя точками.\nВ той статье под \"кратчайшим путём\" понимался путь с минимальным количеством сегментов.\nС другой стороны, в алгоритме Дейкстры каждому сегменту(ребру графа) присваивается число(вес), а алгоритм Дейкстры находит путь с наименьшим суммарным весом.",[1125,6156,6158],{"id":6157},"терминология","Терминология",[554,6160,6161,6162,5986],{},"Разберёмся с терминологией.\nКогда используется алгоритм Дейкстры, с каждым ребром графа связывается число, называемое ",[1095,6163,6164],{},"весом",[554,6166,6167],{},[594,6168],{"alt":6169,"src":6170},"Пример взвешенного графа: веса","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_3.png",[554,6172,6173,6174,6177,6178,6181],{},"Граф с весами называется ",[1095,6175,6176],{},"взвешенным графом",". Граф без весов называется ",[1095,6179,6180],{},"невзвешенным графом",".\nДля вычисления кратчайшего пути в невзвешенном графе используется алгоритм поиска в ширину.\nКратчайшие пути во взвешенном графе вычисляются по алгоритму Дейкстры.",[554,6183,6184],{},"В графах также могут присутствовать циклы.\nЭто означает, что можно из некоторого узла, перемещаться по графу, а потом снова оказаться в том же узле.\nЕсть ли смысл перемещаться по циклу для поиска кратчайшего пути? Правильнее будет использовать путь без прохождения цикла.\nЕсли алгоритму обхода графа пройти по циклу и снова оказаться в том же узле, то цикл лишь добавит лишний вес.\nМожно обойти цикл и два и трижды и т.д., но это лишь добавит лишний вес и увеличит суммарный вес для всего пути.\nСледовательно, путь обхода через цикл или используя цикл — никогда не будет кратчайшим.",[554,6186,6187],{},"Наконец, существует понятие направленных и ненаправленных графов.\nСамо понятие ненаправленного графа означает, что каждый из двух узлов соединённых путём фактически ведёт к другому узлу. Это может быть и цикл.\nВ ненаправленном графе каждое новое ребро добавляет ещё один цикл.\nАлгоритм Дейкстры работает только с графами, в которых нет циклов и где все рёбра неотрицательны.",[554,6189,6190],{},"Далее речь пойдёт о ребрах с положительными весами.",[1125,6192,6194],{"id":6193},"история-одного-обмена","История одного обмена",[554,6196,6197],{},"Рассмотрим конкретный пример. Допустим вы хотите поменять свою книгу на планшет.\nЧтобы успешно произвести такой обмен, необходимо понять как потратить наименьшую сумму по цепочке обменов.\nДопустим у нас есть некоторые предложения от других людей. Изобразим выдуманный пример в виде графа:",[554,6199,6200],{},[594,6201],{"alt":6202,"src":6203},"Пример взвешенного графа обмена","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_4.png",[554,6205,6206],{},"Узлы графа – это предметы, на которые можно поменяться. Веса рёбер представляют сумму доплаты за обмен.\nТаким образом, можно поменять картину на гитару за 300 рублей или же куртку на гитару за 150 рублей(условные суммы).",[554,6208,6209],{},"Как нам вычислить путь от книги до планшета, при котором потратиться наименьшая сумма?\nНа помощь приходит алгоритм Дейкстры! Выполним все 4 шага алгоритма и в конце вычислим итоговый путь по графу.\nПрежде чем начинать, необходимо построить таблицу со стоимостями всех узлов. Таблица будет обновляться по мере работы алгоритма.",[554,6211,6212],{},[594,6213],{"alt":6214,"src":6215},"Таблица взвешенного графа обмена","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_5.png",[554,6217,6218],{},"Для вычисления итогового пути добавляется столбец – родитель. Итак, приступим к выполнению алгоритма:",[554,6220,6221,6223],{},[1095,6222,6093],{}," найти узел с наименьшей стоимостью. В данном случае самый дешёвый вариант обмена с доплатой 0 рублей это картина.\nВозможно ли получить картину с меньшими затратами?\nЭто очень важный момент.\nУдастся ли найти серию обменов, при которой мы получим картину менее чем за 0 рублей(точнее нам ещё заплатят)?\nПравильный ответ: в данном графе это не удастся.\nТак как картина это узел с наименьшей стоимостью, до которого можно добраться и снизить его заданную стоимость нельзя.\nВ этом заключается суть и идея алгоритма Дейкстры: в графе ищется всегда путь с наименьшей стоимостью.\nПути к этому с картиной с меньшими затратами не существует!",[554,6225,6226,6228],{},[1095,6227,6102],{}," вычислить, сколько времени потребуется для того, чтобы добраться до всех соседей(стоимость).",[554,6230,6231],{},[594,6232],{"alt":6233,"src":6234},"Пример взвешенного графа обмена: 2 шага","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_6.png",[554,6236,6237],{},"Стоимости гитары и барабана заносятся в таблицу.\nОни были заданы при переходе через узел картины, поэтому картина указывается как их родитель.\nЭто означает, что для того, чтобы добраться до гитары, вы проходите по ребру от картины; то же самое происходит с барабаном.",[554,6239,6240],{},[594,6241],{"alt":6242,"src":6243},"Таблица взвешенного графа обмена: 2 шага","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_7.png",[554,6245,6246,6249],{},[1095,6247,6248],{},"Снова шаг 1:"," куртка – следующий по стоимости узел(50 рублей).",[554,6251,6252,6255],{},[1095,6253,6254],{},"Снова шаг 2:"," обновляются значения всех его соседей.",[554,6257,6258,6262],{},[594,6259],{"alt":6260,"src":6261},"Пример взвешенного графа обмена: 4 шага","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_8.png",[594,6263],{"alt":6264,"src":6265},"Пример взвешенного таблицы обмена: 4 шага","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_9.png",[554,6267,6268],{},"Смотрите, стоимости барабана и гитары обновились!\nЭто означает, что к барабану и гитаре дешевле перейти через ребро, идущее от куртки.\nСоответственно, куртка назначается новым родителем обоих инструментов.",[554,6270,6271],{},"Следующий по стоимости узел – гитара. Обновите данные его соседей.",[554,6273,6274,6278],{},[594,6275],{"alt":6276,"src":6277},"Пример взвешенного графа обмена: 6 шагов","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_10.png",[594,6279],{"alt":6280,"src":6281},"Пример взвешенного таблицы обмена: 6 шагов","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_11.png",[554,6283,6284],{},"Наконец-то мы вычислили стоимость для планшета при условии обмена гитары на планшет.\nСоответственно, гитара назначается родителем.\nНаконец, задается стоимость последнего узла – барабана.",[554,6286,6287,6291],{},[594,6288],{"alt":6289,"src":6290},"Пример взвешенного графа обмена: 8 шагов","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_12.png",[594,6292],{"alt":6293,"src":6294},"Пример взвешенного таблицы обмена: 8 шагов","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_13.png",[554,6296,6297],{},"Оказывается, вы можете получить планшет дешевле, поменяв барабан на планшет.\nТаким образом, самая дешёвая цепочка обменов обойдётся в 350 рублей.",[554,6299,6300],{},"Теперь, осталось вычислить итоговый путь.\nК этому моменту мы(алгоритм) знаем, что кратчайший путь обойдётся в 350 рублей, но как этот путь определить?",[554,6302,6303],{},"Для начала возьмём родителя для узла \"планшет\".\nВ качестве родителя узла \"планшет\" указан узел \"барабан\".\nА в качестве родителя узла \"барабан\" указан узел \"куртка\".\nСледовательно, вы обмениваете куртку на барабан. И конечно, в самом начале вы меняете книгу на куртку.\nПроходя по родительским узлам в обратном направлении получается полный путь:",[554,6305,6306],{},[594,6307],{"alt":6308,"src":6309},"Пример взвешенного графа обмена: полный путь","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_14.png",[554,6311,6312],{},"Целью этого примера было показать, что кратчайший путь не всегда связывается с физическим расстоянием:\nон может решать задачу минимизации какой-либо характеристики благодаря тому же алгоритму Дейкстры!",[1125,6314,6316],{"id":6315},"рёбра-с-отрицательным-весом","Рёбра с отрицательным весом",[554,6318,6319],{},"Изменим пример выше. Предположим, что существует обмен куртки на картину и при этом вам ещё заплатят 70 рублей.\nВы ничего не тратите при таком обмене, вместо этого вы наоборот получаете!\nИзобразим это на графе:",[554,6321,6322],{},[594,6323],{"alt":6324,"src":6325},"Пример взвешенного графа обмена: с отрицательным ребром","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_15.png",[554,6327,6328],{},"Ребро, ведущее от куртки к картине, имеет отрицательный вес! Получается также, что к картине можно добраться двумя способами.\nА значит что на обмене с отрицательным весом(когда платите не вы, а вам) появляется смысл – вы получите ещё 20 рублей от начальной суммы.\nТеперь, если вы помните, вы можете обменять картину на барабан. И до этого обмена существуют два пути:\nВторой путь обойдётся на 20 рублей дешевле, поэтому нужно выбрать этот путь.\nНо если применить алгоритм Дейкстры к этому графе, то алгоритм выберет неверный путь!\nАлгоритм пойдёт по более длинному пути.\nАлгоритм Дейкстры не может использоваться при наличии рёбер, имеющих отрицательный вес.\nТакие рёбра нарушают работу алгоритма Дейкстры. Посмотрим на пример: начиная с таблицы стоимостей.",[554,6330,6331],{},[594,6332],{"alt":6333,"src":6334},"Пример таблицы обмена: для графа с отрицательным ребром","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_16.png",[554,6336,6337],{},"Теперь найдём узел с наименьшей стоимостью и обновим стоимости его соседей.\nВ этом случае картина оказывается узлом с наименьшей стоимостью.\nВ соответствии с алгоритмом Дейкстры, к картине невозможно перейти более дешёвым способом, чем обменом её на вашу книгу(а видя весь граф вы знаете что это неверно!).\nКак бы то ни было, продолжая пример обновим стоимости соседей картины.",[554,6339,6340],{},[594,6341],{"alt":6342,"src":6343},"Пример таблицы обмена: для графа с отрицательным ребром 2 шага","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_17.png",[554,6345,6346],{},"Получается, что теперь стоимость барабана составляет 350 рублей.\nПерейдём к следующему по стоимости узлу, который ещё не был обработан – это куртка. Обновим стоимости её соседей.",[554,6348,6349],{},[594,6350],{"alt":6351,"src":6352},"Пример таблицы обмена: для графа с отрицательным ребром 4 шага","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_18.png",[554,6354,6355],{},"Узел \"картина\" уже был обработан, однако алгоритм обновляет его стоимость.\nЭто очень плохой признак – обработка узла означает, что к нему невозможно добраться с меньшими затратами.\nНо вы самостоятельно уже нашли более \"дешёвый\" путь к картине.\nУ барабана соседей нет, поэтому работа алгоритма завершается.\nНиже покажем итоговые стоимости согласно алгоритму Дейкстры:",[554,6357,6358],{},[594,6359],{"alt":6360,"src":6361},"Пример таблицы обмена: для графа с отрицательным ребром итог","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_19.png",[554,6363,6364,6365,6370,6371,6376],{},"Чтобы добраться до барабана, вам потребовалось 350 рублей.\nВы знаете, что существует путь, который стоит всего 330 рублей, но алгоритм Дейкстры его не находит.\nАлгоритм Дейкстры сразу предположил, что, поскольку вы обрабатываете узел \"картина\", к этому узлу невозможно добраться быстрее!\nЭто предположение работает только в том случае, если рёбер с отрицательным весом не существует.\nСледовательно, ",[4577,6366,6367],{},[1095,6368,6369],{},"использование алгоритма Дейкстры с графом, содержащим рёбра с отрицательным весом — невозможно",".\nВ случае с отрицательными весами понадобится алгоритм ",[558,6372,6375],{"href":6373,"rel":6374},"https:\u002F\u002Fru.wikipedia.org\u002Fwiki\u002F%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",[1264],"Беллмана — Форда",".\nРассмотрение алгоритма Беллмана — Форда выходит за рамки этой статьи.\nЗаймёмся теперь реализацией алгоритма Дейкстры.",[1125,6378,6380],{"id":6379},"реализация-алгоритма-дейкстры","Реализация алгоритма Дейкстры",[554,6382,6383],{},"Ниже изображён граф, который будет использоваться в примере с кодом:",[554,6385,6386],{},[594,6387],{"alt":6388,"src":6389},"Пример взвешенного графа: реализация","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_20.png",[554,6391,6392],{},"Для реализации понадобятся три хеш-таблицы или три словаря в Python.\nСловари стоимостей и родителей будут обновляться по ходу работы алгоритма.\nСначала необходимо реализовать словарь для графа:",[3310,6394,6396],{"className":3312,"code":6395,"language":3314,"meta":982,"style":982},"graph = {}\n",[3316,6397,6398],{"__ignoreMap":982},[3319,6399,6400,6403,6405],{"class":3321,"line":3322},[3319,6401,6402],{"class":3325},"graph ",[3319,6404,3330],{"class":3329},[3319,6406,4992],{"class":3325},[554,6408,6409],{},"Необходимо сохранить соседей и стоимость перехода. Судя по графу у начального узла есть два соседа, A и B.\nВеса рёбер графа также представим виде хеш-таблицы или словаря:",[3310,6411,6413],{"className":3312,"code":6412,"language":3314,"meta":982,"style":982},"graph[\"start\"] = {}\ngraph[\"start\"][\"a\"] = 6\ngraph[\"start\"][\"b\"] = 2\n",[3316,6414,6415,6429,6447],{"__ignoreMap":982},[3319,6416,6417,6420,6423,6425,6427],{"class":3321,"line":3322},[3319,6418,6419],{"class":3325},"graph[",[3319,6421,6422],{"class":3336},"\"start\"",[3319,6424,3519],{"class":3325},[3319,6426,3330],{"class":3329},[3319,6428,4992],{"class":3325},[3319,6430,6431,6433,6435,6438,6440,6442,6444],{"class":3321,"line":1443},[3319,6432,6419],{"class":3325},[3319,6434,6422],{"class":3336},[3319,6436,6437],{"class":3325},"][",[3319,6439,3630],{"class":3336},[3319,6441,3519],{"class":3325},[3319,6443,3330],{"class":3329},[3319,6445,6446],{"class":3394}," 6\n",[3319,6448,6449,6451,6453,6455,6458,6460,6462],{"class":3321,"line":1458},[3319,6450,6419],{"class":3325},[3319,6452,6422],{"class":3336},[3319,6454,6437],{"class":3325},[3319,6456,6457],{"class":3336},"\"b\"",[3319,6459,3519],{"class":3325},[3319,6461,3330],{"class":3329},[3319,6463,6464],{"class":3394}," 2\n",[554,6466,6467,6468,6471],{},"Итак, ",[3316,6469,6470],{},"graph[\"start\"]"," является словарём. Для получения всех соседей узла можно воспользоваться следующим выражением:",[3310,6473,6475],{"className":3312,"code":6474,"language":3314,"meta":982,"style":982},"print(list(graph[\"start\"].keys()))\n# [\"a\", \"b\"]\n",[3316,6476,6477,6494],{"__ignoreMap":982},[3319,6478,6479,6481,6483,6486,6489,6491],{"class":3321,"line":3322},[3319,6480,5742],{"class":3394},[3319,6482,3409],{"class":3325},[3319,6484,6485],{"class":3394},"list",[3319,6487,6488],{"class":3325},"(graph[",[3319,6490,6422],{"class":3336},[3319,6492,6493],{"class":3325},"].keys()))\n",[3319,6495,6496],{"class":3321,"line":1443},[3319,6497,6498],{"class":3493},"# [\"a\", \"b\"]\n",[554,6500,6501],{},"Одно ребро ведёт из начального узла в A, а другое из начального узла в B. Веса узнать этих рёбер можно так:",[3310,6503,6505],{"className":3312,"code":6504,"language":3314,"meta":982,"style":982},"print(graph[\"start\"][\"a\"]) # 6\nprint(graph[\"start\"][\"b\"]) # 2\n",[3316,6506,6507,6525],{"__ignoreMap":982},[3319,6508,6509,6511,6513,6515,6517,6519,6522],{"class":3321,"line":3322},[3319,6510,5742],{"class":3394},[3319,6512,6488],{"class":3325},[3319,6514,6422],{"class":3336},[3319,6516,6437],{"class":3325},[3319,6518,3630],{"class":3336},[3319,6520,6521],{"class":3325},"]) ",[3319,6523,6524],{"class":3493},"# 6\n",[3319,6526,6527,6529,6531,6533,6535,6537,6539],{"class":3321,"line":1443},[3319,6528,5742],{"class":3394},[3319,6530,6488],{"class":3325},[3319,6532,6422],{"class":3336},[3319,6534,6437],{"class":3325},[3319,6536,6457],{"class":3336},[3319,6538,6521],{"class":3325},[3319,6540,6541],{"class":3493},"# 2\n",[554,6543,6544],{},"Допишем в граф остальные узлы:",[3310,6546,6548],{"className":3312,"code":6547,"language":3314,"meta":982,"style":982},"graph[\"a\"] = {}\ngraph[\"a\"][\"final\"] = 1\ngraph[\"b\"] = {}\ngraph[\"b\"][\"a\"] = 3\ngraph[\"b\"][\"final\"] = 5\ngraph[\"final\"] = {}  # У конечного узла соседей нет\n",[3316,6549,6550,6562,6579,6591,6608,6625],{"__ignoreMap":982},[3319,6551,6552,6554,6556,6558,6560],{"class":3321,"line":3322},[3319,6553,6419],{"class":3325},[3319,6555,3630],{"class":3336},[3319,6557,3519],{"class":3325},[3319,6559,3330],{"class":3329},[3319,6561,4992],{"class":3325},[3319,6563,6564,6566,6568,6570,6573,6575,6577],{"class":3321,"line":1443},[3319,6565,6419],{"class":3325},[3319,6567,3630],{"class":3336},[3319,6569,6437],{"class":3325},[3319,6571,6572],{"class":3336},"\"final\"",[3319,6574,3519],{"class":3325},[3319,6576,3330],{"class":3329},[3319,6578,3525],{"class":3394},[3319,6580,6581,6583,6585,6587,6589],{"class":3321,"line":1458},[3319,6582,6419],{"class":3325},[3319,6584,6457],{"class":3336},[3319,6586,3519],{"class":3325},[3319,6588,3330],{"class":3329},[3319,6590,4992],{"class":3325},[3319,6592,6593,6595,6597,6599,6601,6603,6605],{"class":3321,"line":1449},[3319,6594,6419],{"class":3325},[3319,6596,6457],{"class":3336},[3319,6598,6437],{"class":3325},[3319,6600,3630],{"class":3336},[3319,6602,3519],{"class":3325},[3319,6604,3330],{"class":3329},[3319,6606,6607],{"class":3394}," 3\n",[3319,6609,6610,6612,6614,6616,6618,6620,6622],{"class":3321,"line":1444},[3319,6611,6419],{"class":3325},[3319,6613,6457],{"class":3336},[3319,6615,6437],{"class":3325},[3319,6617,6572],{"class":3336},[3319,6619,3519],{"class":3325},[3319,6621,3330],{"class":3329},[3319,6623,6624],{"class":3394}," 5\n",[3319,6626,6627,6629,6631,6633,6635,6638],{"class":3321,"line":3478},[3319,6628,6419],{"class":3325},[3319,6630,6572],{"class":3336},[3319,6632,3519],{"class":3325},[3319,6634,3330],{"class":3329},[3319,6636,6637],{"class":3325}," {}  ",[3319,6639,6640],{"class":3493},"# У конечного узла соседей нет\n",[554,6642,6643,6644,6647],{},"Стоимость узла определяет, сколько времени потребуется для перехода к этому узлу от начального узла.\nВы не знаете, сколько времени потребуется для достижения конечного узла. Если стоимость ещё неизвестна, она считается бесконечной.\nКак представить бесконечно в Python? Есть следующий вариант: ",[3316,6645,6646],{},"infinity = math.inf",".\nКод создания словаря стоимостей:",[3310,6649,6651],{"className":3312,"code":6650,"language":3314,"meta":982,"style":982},"import math\ninfinity = math.inf\ncosts = {}\ncosts[\"a\"] = 6\ncosts[\"b\"] = 2\ncosts[\"final\"] = infinity\n",[3316,6652,6653,6661,6671,6680,6693,6705],{"__ignoreMap":982},[3319,6654,6655,6658],{"class":3321,"line":3322},[3319,6656,6657],{"class":3329},"import",[3319,6659,6660],{"class":3325}," math\n",[3319,6662,6663,6666,6668],{"class":3321,"line":1443},[3319,6664,6665],{"class":3325},"infinity ",[3319,6667,3330],{"class":3329},[3319,6669,6670],{"class":3325}," math.inf\n",[3319,6672,6673,6676,6678],{"class":3321,"line":1458},[3319,6674,6675],{"class":3325},"costs ",[3319,6677,3330],{"class":3329},[3319,6679,4992],{"class":3325},[3319,6681,6682,6685,6687,6689,6691],{"class":3321,"line":1449},[3319,6683,6684],{"class":3325},"costs[",[3319,6686,3630],{"class":3336},[3319,6688,3519],{"class":3325},[3319,6690,3330],{"class":3329},[3319,6692,6446],{"class":3394},[3319,6694,6695,6697,6699,6701,6703],{"class":3321,"line":1444},[3319,6696,6684],{"class":3325},[3319,6698,6457],{"class":3336},[3319,6700,3519],{"class":3325},[3319,6702,3330],{"class":3329},[3319,6704,6464],{"class":3394},[3319,6706,6707,6709,6711,6713,6715],{"class":3321,"line":3478},[3319,6708,6684],{"class":3325},[3319,6710,6572],{"class":3336},[3319,6712,3519],{"class":3325},[3319,6714,3330],{"class":3329},[3319,6716,6717],{"class":3325}," infinity\n",[554,6719,6720],{},"Для родителей также создадим отдельный словарь. Код представлен ниже:",[3310,6722,6724],{"className":3312,"code":6723,"language":3314,"meta":982,"style":982},"parents = {}\nparents[\"a\"] = \"start\"\nparents[\"b\"] = \"start\"\nparents[\"final\"] = None\n",[3316,6725,6726,6735,6749,6761],{"__ignoreMap":982},[3319,6727,6728,6731,6733],{"class":3321,"line":3322},[3319,6729,6730],{"class":3325},"parents ",[3319,6732,3330],{"class":3329},[3319,6734,4992],{"class":3325},[3319,6736,6737,6740,6742,6744,6746],{"class":3321,"line":1443},[3319,6738,6739],{"class":3325},"parents[",[3319,6741,3630],{"class":3336},[3319,6743,3519],{"class":3325},[3319,6745,3330],{"class":3329},[3319,6747,6748],{"class":3336}," \"start\"\n",[3319,6750,6751,6753,6755,6757,6759],{"class":3321,"line":1458},[3319,6752,6739],{"class":3325},[3319,6754,6457],{"class":3336},[3319,6756,3519],{"class":3325},[3319,6758,3330],{"class":3329},[3319,6760,6748],{"class":3336},[3319,6762,6763,6765,6767,6769,6771],{"class":3321,"line":1449},[3319,6764,6739],{"class":3325},[3319,6766,6572],{"class":3336},[3319,6768,3519],{"class":3325},[3319,6770,3330],{"class":3329},[3319,6772,5173],{"class":3394},[554,6774,6775],{},"Наконец, нужно множество для отслеживания всех уже обработанных узлов, так как один узел не должен обрабатываться многократно:",[3310,6777,6779],{"className":3312,"code":6778,"language":3314,"meta":982,"style":982},"processed = set()\n",[3316,6780,6781],{"__ignoreMap":982},[3319,6782,6783,6786,6788,6790],{"class":3321,"line":3322},[3319,6784,6785],{"class":3325},"processed ",[3319,6787,3330],{"class":3329},[3319,6789,4931],{"class":3394},[3319,6791,5140],{"class":3325},[554,6793,6794],{},"На этом подготовка для данных завершена. Ниже напишем код алгоритма:",[3310,6796,6798],{"className":3312,"code":6797,"language":3314,"meta":982,"style":982},"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",[3316,6799,6800,6813,6832,6845,6858,6873,6891,6906,6919,6931,6939],{"__ignoreMap":982},[3319,6801,6802,6805,6807,6810],{"class":3321,"line":3322},[3319,6803,6804],{"class":3325},"node ",[3319,6806,3330],{"class":3329},[3319,6808,6809],{"class":3325}," find_lowest_cost(costs) ",[3319,6811,6812],{"class":3493},"# Найти узел с наименьшей стоимостью среди необработанных\n",[3319,6814,6815,6817,6820,6822,6824,6826,6829],{"class":3321,"line":1443},[3319,6816,5160],{"class":3329},[3319,6818,6819],{"class":3325}," node ",[3319,6821,5700],{"class":3329},[3319,6823,5703],{"class":3329},[3319,6825,5706],{"class":3394},[3319,6827,6828],{"class":3325},": ",[3319,6830,6831],{"class":3493},"# Обрабатываем все узлы\n",[3319,6833,6834,6837,6839,6842],{"class":3321,"line":1458},[3319,6835,6836],{"class":3325},"  cost ",[3319,6838,3330],{"class":3329},[3319,6840,6841],{"class":3325}," costs[node] ",[3319,6843,6844],{"class":3493},"# Получить стоимость\n",[3319,6846,6847,6850,6852,6855],{"class":3321,"line":1449},[3319,6848,6849],{"class":3325},"  neighbors ",[3319,6851,3330],{"class":3329},[3319,6853,6854],{"class":3325}," graph[node] ",[3319,6856,6857],{"class":3493},"# Получить соседей узла\n",[3319,6859,6860,6862,6865,6867,6870],{"class":3321,"line":1444},[3319,6861,5189],{"class":3329},[3319,6863,6864],{"class":3325}," n ",[3319,6866,3403],{"class":3329},[3319,6868,6869],{"class":3325}," neighbors.keys(): ",[3319,6871,6872],{"class":3493},"# Перебор всех соседей текущего узла\n",[3319,6874,6875,6878,6880,6883,6885,6888],{"class":3321,"line":3478},[3319,6876,6877],{"class":3325},"    new_cost ",[3319,6879,3330],{"class":3329},[3319,6881,6882],{"class":3325}," cost ",[3319,6884,3522],{"class":3329},[3319,6886,6887],{"class":3325}," neighbors[n] ",[3319,6889,6890],{"class":3493},"# Вычисляем стоимость пути перехода\n",[3319,6892,6893,6895,6898,6900,6903],{"class":3321,"line":3497},[3319,6894,5643],{"class":3329},[3319,6896,6897],{"class":3325}," costs[n] ",[3319,6899,5252],{"class":3329},[3319,6901,6902],{"class":3325}," new_cost: ",[3319,6904,6905],{"class":3493},"# Если к соседу можно добрать быстрее через текущий узел\n",[3319,6907,6908,6911,6913,6916],{"class":3321,"line":3528},[3319,6909,6910],{"class":3325},"      costs[n] ",[3319,6912,3330],{"class":3329},[3319,6914,6915],{"class":3325}," new_cost ",[3319,6917,6918],{"class":3493},"# Обновить стоимость узла\n",[3319,6920,6921,6924,6926,6928],{"class":3321,"line":3540},[3319,6922,6923],{"class":3325},"      parents[n] ",[3319,6925,3330],{"class":3329},[3319,6927,6819],{"class":3325},[3319,6929,6930],{"class":3493},"# Этот узел становится новым родителем для соседа\n",[3319,6932,6933,6936],{"class":3321,"line":3550},[3319,6934,6935],{"class":3325},"  processed.add(node) ",[3319,6937,6938],{"class":3493},"# Узел помечается как обработанный\n",[3319,6940,6941,6944,6946,6948],{"class":3321,"line":3562},[3319,6942,6943],{"class":3325},"  node ",[3319,6945,3330],{"class":3329},[3319,6947,6809],{"class":3325},[3319,6949,6950],{"class":3493},"# Найти следующий узел для обработки\n",[554,6952,6953,6954,6957],{},"После того как все узлы будут обработаны, алгоритм завершается. Код функции ",[3316,6955,6956],{},"find_lowest_cost(costs)"," приведём ниже:",[3310,6959,6961],{"className":3312,"code":6960,"language":3314,"meta":982,"style":982},"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",[3316,6962,6963,6975,6984,6993,7007,7017,7043,7055,7065],{"__ignoreMap":982},[3319,6964,6965,6968,6972],{"class":3321,"line":3322},[3319,6966,6967],{"class":3329},"def",[3319,6969,6971],{"class":6970},"s7eDp"," find_lowest_cost",[3319,6973,6974],{"class":3325},"(costs):\n",[3319,6976,6977,6980,6982],{"class":3321,"line":1443},[3319,6978,6979],{"class":3325},"  lowest_cost ",[3319,6981,3330],{"class":3329},[3319,6983,6670],{"class":3325},[3319,6985,6986,6989,6991],{"class":3321,"line":1458},[3319,6987,6988],{"class":3325},"  lowest_cost_node ",[3319,6990,3330],{"class":3329},[3319,6992,5173],{"class":3394},[3319,6994,6995,6997,6999,7001,7004],{"class":3321,"line":1449},[3319,6996,5189],{"class":3329},[3319,6998,6819],{"class":3325},[3319,7000,3403],{"class":3329},[3319,7002,7003],{"class":3325}," costs: ",[3319,7005,7006],{"class":3493},"# Перебираем все узлы\n",[3319,7008,7009,7012,7014],{"class":3321,"line":1444},[3319,7010,7011],{"class":3325},"    cost ",[3319,7013,3330],{"class":3329},[3319,7015,7016],{"class":3325}," costs[node]\n",[3319,7018,7019,7021,7023,7026,7029,7031,7033,7035,7037,7040],{"class":3321,"line":3478},[3319,7020,5643],{"class":3329},[3319,7022,6882],{"class":3325},[3319,7024,7025],{"class":3329},"\u003C",[3319,7027,7028],{"class":3325}," lowest_cost ",[3319,7030,5657],{"class":3329},[3319,7032,6819],{"class":3325},[3319,7034,5663],{"class":3329},[3319,7036,5666],{"class":3329},[3319,7038,7039],{"class":3325}," processed: ",[3319,7041,7042],{"class":3493},"# Если узел с наименьшей стоимость и ещё не был обработан\n",[3319,7044,7045,7048,7050,7052],{"class":3321,"line":3497},[3319,7046,7047],{"class":3325},"      lowest_cost ",[3319,7049,3330],{"class":3329},[3319,7051,6882],{"class":3325},[3319,7053,7054],{"class":3493},"# он назначается новым узлом с наименьшей стоимостью\n",[3319,7056,7057,7060,7062],{"class":3321,"line":3528},[3319,7058,7059],{"class":3325},"      lowest_cost_node ",[3319,7061,3330],{"class":3329},[3319,7063,7064],{"class":3325}," node\n",[3319,7066,7067,7070],{"class":3321,"line":3540},[3319,7068,7069],{"class":3329},"  return",[3319,7071,7072],{"class":3325}," lowest_cost_node\n",[554,7074,7075],{},"Чтобы найти узел с наименьшей стоимостью, мы каждый раз перебираем все узлы. Существует более эффективный вариант этого алгоритма.\nОн использует структуру данных, называемую очередью с приоритетом. Эта очередь строится на основе другой структуры данных — кучи.\nЕсли вам интересны очереди с приоритетом и кучи, об этом будет далее статья.",[554,7077,7078],{},"Объединим весь код:",[3310,7080,7082],{"className":3312,"code":7081,"language":3314,"meta":982,"style":982},"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",[3316,7083,7084,7090,7094,7102,7114,7130,7146,7158,7174,7186,7202,7218,7230,7234,7242,7250,7262,7274,7286,7290,7298,7310,7322,7334,7338,7348,7352,7361,7370,7379,7391,7400,7422,7431,7439,7445,7450,7460,7475,7484,7493,7505,7519,7531,7541,7550,7556,7565,7570,7583],{"__ignoreMap":982},[3319,7085,7086,7088],{"class":3321,"line":3322},[3319,7087,6657],{"class":3329},[3319,7089,6660],{"class":3325},[3319,7091,7092],{"class":3321,"line":1443},[3319,7093,5439],{"emptyLinePlaceholder":513},[3319,7095,7096,7098,7100],{"class":3321,"line":1458},[3319,7097,6402],{"class":3325},[3319,7099,3330],{"class":3329},[3319,7101,4992],{"class":3325},[3319,7103,7104,7106,7108,7110,7112],{"class":3321,"line":1449},[3319,7105,6419],{"class":3325},[3319,7107,6422],{"class":3336},[3319,7109,3519],{"class":3325},[3319,7111,3330],{"class":3329},[3319,7113,4992],{"class":3325},[3319,7115,7116,7118,7120,7122,7124,7126,7128],{"class":3321,"line":1444},[3319,7117,6419],{"class":3325},[3319,7119,6422],{"class":3336},[3319,7121,6437],{"class":3325},[3319,7123,3630],{"class":3336},[3319,7125,3519],{"class":3325},[3319,7127,3330],{"class":3329},[3319,7129,6446],{"class":3394},[3319,7131,7132,7134,7136,7138,7140,7142,7144],{"class":3321,"line":3478},[3319,7133,6419],{"class":3325},[3319,7135,6422],{"class":3336},[3319,7137,6437],{"class":3325},[3319,7139,6457],{"class":3336},[3319,7141,3519],{"class":3325},[3319,7143,3330],{"class":3329},[3319,7145,6464],{"class":3394},[3319,7147,7148,7150,7152,7154,7156],{"class":3321,"line":3497},[3319,7149,6419],{"class":3325},[3319,7151,3630],{"class":3336},[3319,7153,3519],{"class":3325},[3319,7155,3330],{"class":3329},[3319,7157,4992],{"class":3325},[3319,7159,7160,7162,7164,7166,7168,7170,7172],{"class":3321,"line":3528},[3319,7161,6419],{"class":3325},[3319,7163,3630],{"class":3336},[3319,7165,6437],{"class":3325},[3319,7167,6572],{"class":3336},[3319,7169,3519],{"class":3325},[3319,7171,3330],{"class":3329},[3319,7173,3525],{"class":3394},[3319,7175,7176,7178,7180,7182,7184],{"class":3321,"line":3540},[3319,7177,6419],{"class":3325},[3319,7179,6457],{"class":3336},[3319,7181,3519],{"class":3325},[3319,7183,3330],{"class":3329},[3319,7185,4992],{"class":3325},[3319,7187,7188,7190,7192,7194,7196,7198,7200],{"class":3321,"line":3550},[3319,7189,6419],{"class":3325},[3319,7191,6457],{"class":3336},[3319,7193,6437],{"class":3325},[3319,7195,3630],{"class":3336},[3319,7197,3519],{"class":3325},[3319,7199,3330],{"class":3329},[3319,7201,6607],{"class":3394},[3319,7203,7204,7206,7208,7210,7212,7214,7216],{"class":3321,"line":3562},[3319,7205,6419],{"class":3325},[3319,7207,6457],{"class":3336},[3319,7209,6437],{"class":3325},[3319,7211,6572],{"class":3336},[3319,7213,3519],{"class":3325},[3319,7215,3330],{"class":3329},[3319,7217,6624],{"class":3394},[3319,7219,7220,7222,7224,7226,7228],{"class":3321,"line":5576},[3319,7221,6419],{"class":3325},[3319,7223,6572],{"class":3336},[3319,7225,3519],{"class":3325},[3319,7227,3330],{"class":3329},[3319,7229,4992],{"class":3325},[3319,7231,7232],{"class":3321,"line":5587},[3319,7233,5439],{"emptyLinePlaceholder":513},[3319,7235,7236,7238,7240],{"class":3321,"line":5594},[3319,7237,6665],{"class":3325},[3319,7239,3330],{"class":3329},[3319,7241,6670],{"class":3325},[3319,7243,7244,7246,7248],{"class":3321,"line":5603},[3319,7245,6675],{"class":3325},[3319,7247,3330],{"class":3329},[3319,7249,4992],{"class":3325},[3319,7251,7252,7254,7256,7258,7260],{"class":3321,"line":5614},[3319,7253,6684],{"class":3325},[3319,7255,3630],{"class":3336},[3319,7257,3519],{"class":3325},[3319,7259,3330],{"class":3329},[3319,7261,6446],{"class":3394},[3319,7263,7264,7266,7268,7270,7272],{"class":3321,"line":5625},[3319,7265,6684],{"class":3325},[3319,7267,6457],{"class":3336},[3319,7269,3519],{"class":3325},[3319,7271,3330],{"class":3329},[3319,7273,6464],{"class":3394},[3319,7275,7276,7278,7280,7282,7284],{"class":3321,"line":5640},[3319,7277,6684],{"class":3325},[3319,7279,6572],{"class":3336},[3319,7281,3519],{"class":3325},[3319,7283,3330],{"class":3329},[3319,7285,6717],{"class":3325},[3319,7287,7288],{"class":3321,"line":5672},[3319,7289,5439],{"emptyLinePlaceholder":513},[3319,7291,7292,7294,7296],{"class":3321,"line":5682},[3319,7293,6730],{"class":3325},[3319,7295,3330],{"class":3329},[3319,7297,4992],{"class":3325},[3319,7299,7300,7302,7304,7306,7308],{"class":3321,"line":5692},[3319,7301,6739],{"class":3325},[3319,7303,3630],{"class":3336},[3319,7305,3519],{"class":3325},[3319,7307,3330],{"class":3329},[3319,7309,6748],{"class":3336},[3319,7311,7312,7314,7316,7318,7320],{"class":3321,"line":5711},[3319,7313,6739],{"class":3325},[3319,7315,6457],{"class":3336},[3319,7317,3519],{"class":3325},[3319,7319,3330],{"class":3329},[3319,7321,6748],{"class":3336},[3319,7323,7324,7326,7328,7330,7332],{"class":3321,"line":5721},[3319,7325,6739],{"class":3325},[3319,7327,6572],{"class":3336},[3319,7329,3519],{"class":3325},[3319,7331,3330],{"class":3329},[3319,7333,5173],{"class":3394},[3319,7335,7336],{"class":3321,"line":5727},[3319,7337,5439],{"emptyLinePlaceholder":513},[3319,7339,7340,7342,7344,7346],{"class":3321,"line":5733},[3319,7341,6785],{"class":3325},[3319,7343,3330],{"class":3329},[3319,7345,4931],{"class":3394},[3319,7347,5140],{"class":3325},[3319,7349,7350],{"class":3321,"line":5739},[3319,7351,5439],{"emptyLinePlaceholder":513},[3319,7353,7355,7357,7359],{"class":3321,"line":7354},27,[3319,7356,6967],{"class":3329},[3319,7358,6971],{"class":6970},[3319,7360,6974],{"class":3325},[3319,7362,7364,7366,7368],{"class":3321,"line":7363},28,[3319,7365,6979],{"class":3325},[3319,7367,3330],{"class":3329},[3319,7369,6670],{"class":3325},[3319,7371,7373,7375,7377],{"class":3321,"line":7372},29,[3319,7374,6988],{"class":3325},[3319,7376,3330],{"class":3329},[3319,7378,5173],{"class":3394},[3319,7380,7382,7384,7386,7388],{"class":3321,"line":7381},30,[3319,7383,5189],{"class":3329},[3319,7385,6819],{"class":3325},[3319,7387,3403],{"class":3329},[3319,7389,7390],{"class":3325}," costs:\n",[3319,7392,7394,7396,7398],{"class":3321,"line":7393},31,[3319,7395,7011],{"class":3325},[3319,7397,3330],{"class":3329},[3319,7399,7016],{"class":3325},[3319,7401,7403,7405,7407,7409,7411,7413,7415,7417,7419],{"class":3321,"line":7402},32,[3319,7404,5643],{"class":3329},[3319,7406,6882],{"class":3325},[3319,7408,7025],{"class":3329},[3319,7410,7028],{"class":3325},[3319,7412,5657],{"class":3329},[3319,7414,6819],{"class":3325},[3319,7416,5663],{"class":3329},[3319,7418,5666],{"class":3329},[3319,7420,7421],{"class":3325}," processed:\n",[3319,7423,7424,7426,7428],{"class":3321,"line":6023},[3319,7425,7047],{"class":3325},[3319,7427,3330],{"class":3329},[3319,7429,7430],{"class":3325}," cost\n",[3319,7432,7433,7435,7437],{"class":3321,"line":4633},[3319,7434,7059],{"class":3325},[3319,7436,3330],{"class":3329},[3319,7438,7064],{"class":3325},[3319,7440,7441,7443],{"class":3321,"line":1487},[3319,7442,7069],{"class":3329},[3319,7444,7072],{"class":3325},[3319,7446,7448],{"class":3321,"line":7447},36,[3319,7449,5439],{"emptyLinePlaceholder":513},[3319,7451,7453,7455,7457],{"class":3321,"line":7452},37,[3319,7454,6804],{"class":3325},[3319,7456,3330],{"class":3329},[3319,7458,7459],{"class":3325}," find_lowest_cost(costs)\n",[3319,7461,7463,7465,7467,7469,7471,7473],{"class":3321,"line":7462},38,[3319,7464,5160],{"class":3329},[3319,7466,6819],{"class":3325},[3319,7468,5700],{"class":3329},[3319,7470,5703],{"class":3329},[3319,7472,5706],{"class":3394},[3319,7474,3754],{"class":3325},[3319,7476,7478,7480,7482],{"class":3321,"line":7477},39,[3319,7479,6836],{"class":3325},[3319,7481,3330],{"class":3329},[3319,7483,7016],{"class":3325},[3319,7485,7486,7488,7490],{"class":3321,"line":4632},[3319,7487,6849],{"class":3325},[3319,7489,3330],{"class":3329},[3319,7491,7492],{"class":3325}," graph[node]\n",[3319,7494,7496,7498,7500,7502],{"class":3321,"line":7495},41,[3319,7497,5189],{"class":3329},[3319,7499,6864],{"class":3325},[3319,7501,3403],{"class":3329},[3319,7503,7504],{"class":3325}," neighbors.keys():\n",[3319,7506,7508,7510,7512,7514,7516],{"class":3321,"line":7507},42,[3319,7509,6877],{"class":3325},[3319,7511,3330],{"class":3329},[3319,7513,6882],{"class":3325},[3319,7515,3522],{"class":3329},[3319,7517,7518],{"class":3325}," neighbors[n]\n",[3319,7520,7522,7524,7526,7528],{"class":3321,"line":7521},43,[3319,7523,5643],{"class":3329},[3319,7525,6897],{"class":3325},[3319,7527,5252],{"class":3329},[3319,7529,7530],{"class":3325}," new_cost:\n",[3319,7532,7534,7536,7538],{"class":3321,"line":7533},44,[3319,7535,6910],{"class":3325},[3319,7537,3330],{"class":3329},[3319,7539,7540],{"class":3325}," new_cost\n",[3319,7542,7544,7546,7548],{"class":3321,"line":7543},45,[3319,7545,6923],{"class":3325},[3319,7547,3330],{"class":3329},[3319,7549,7064],{"class":3325},[3319,7551,7553],{"class":3321,"line":7552},46,[3319,7554,7555],{"class":3325},"  processed.add(node)\n",[3319,7557,7559,7561,7563],{"class":3321,"line":7558},47,[3319,7560,6943],{"class":3325},[3319,7562,3330],{"class":3329},[3319,7564,7459],{"class":3325},[3319,7566,7568],{"class":3321,"line":7567},48,[3319,7569,5439],{"emptyLinePlaceholder":513},[3319,7571,7573,7575,7577,7580],{"class":3321,"line":7572},49,[3319,7574,5742],{"class":3394},[3319,7576,3409],{"class":3325},[3319,7578,7579],{"class":3336},"\"Стоимость от начала до каждого узла:\"",[3319,7581,7582],{"class":3325},")\n",[3319,7584,7586,7588],{"class":3321,"line":7585},50,[3319,7587,5742],{"class":3394},[3319,7589,7590],{"class":3325},"(costs)\n",[551,7592,7593],{},[554,7594,7595,7596,5986],{},"В следующей статье информация про ",[558,7597,7598],{"href":295},"жадные алгоритмы",[566,7600],{"id":982},[546,7602],{":isList":7603,"title":1208},"[\"Поиск в ширину вычисляет кратчайший путь в невзвешенном графе;\",\"Алгоритм Дейкстры вычисляет кратчайший путь во взвешенном графе;\",\"Алгоритм Дейкстры работает только в том случае, если все веса положительны;\",\"При наличии отрицательных весов используйте алгоритм Беллмана – Форда.\"]",[554,7605,4575,7606,4580,7608,4584],{},[4577,7607,4579],{},[4577,7609,4583],{},[4586,7611],{},[1439,7613,7614],{},"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":982,"searchDepth":1443,"depth":1444,"links":7616},[7617],{"id":6034,"depth":1443,"text":290,"children":7618},[7619,7620,7621,7622,7623],{"id":6061,"depth":1458,"text":6062},{"id":6157,"depth":1458,"text":6158},{"id":6193,"depth":1458,"text":6194},{"id":6315,"depth":1458,"text":6316},{"id":6379,"depth":1458,"text":6380,"children":7624},[7625],{"id":982,"depth":1449,"text":982},"2026-04-16","Взвешенные графы. Поиск кратчайшего пути.","images\u002Fblog\u002Fpython\u002Fst32\u002Fimg.png",{},{"title":290,"description":7627},"oTvaHqETJhriQRlvN68W5R7V5FrO0Qtxg1aRx-2exjI",{"id":7633,"title":286,"author":7634,"body":7636,"date":8035,"description":8036,"extension":1484,"image":8037,"meta":8038,"minRead":5721,"navigation":513,"num":7393,"path":287,"seo":8039,"stem":288,"__hash__":8040},"blog\u002Fblog\u002Fpython\u002Fst31.md",{"name":516,"avatar":7635},{"src":536,"alt":537},{"type":539,"value":7637,"toc":8019},[7638,7641,7644,7656,7659,7663,7681,7685,7688,7694,7701,7704,7707,7719,7727,7744,7748,7757,7761,7764,7770,7773,7778,7781,7786,7789,7794,7797,7802,7805,7810,7813,7817,7824,7830,7833,7836,7841,7844,7849,7852,7857,7860,7865,7868,7876,7879,7921,7925,7943,7947,7950,7956,7959,7967,7970,7974,7981,7984,7987,7990,7993,7998,8001,8004,8014,8016],[542,7639,286],{"id":7640},"сбалансированные-деревья",[546,7642],{":isList":7643,"title":549},"[\"Узнаете о структуре данных, называемой бинарным деревом поиска (BST, Binary Search Tree).\",\"Разберётесь почему сбалансированные деревья часто бывают эффективнее массивов и связанных списков.\",\"Узнаете о АВЛ-деревьях — разновидности сбалансированного дерева BST.\"]",[551,7645,7646],{},[554,7647,7648,7649,7651,7652,7655],{},"В предыдущих статьях были рассмотрены два подхода и алгоритмы для поиска по деревьям: ",[558,7650,6051],{"href":275}," и ",[558,7653,7654],{"href":283},"поиск в глубину",".\nЗдесь далее текст пойдёт о сбалансированных деревьях.",[554,7657,7658],{},"Если связанные списки и массивы не дают нужной производительности, целесообразно обратиться к структуре графов.\nРассмотрим, какой производительности можно добиться с помощью деревьев.\nОтличную производительность могут обеспечивать так называемые сбалансированные деревья.",[1125,7660,7662],{"id":7661},"балансировка","Балансировка",[554,7664,7665,7666,7668,7669,7671,7672,7674,7675,7677,7678,7680],{},"Помните бинарный поиск?\nС его помощью можно найти информацию намного быстрее, чем простым поиском — со сложностью ",[1095,7667,1424],{}," вместо ",[1095,7670,1279],{},".\nНо, есть одна проблема: вставка.\nКонечно, поиск занимает время ",[1095,7673,1424],{},", но массив должен быть отсортирован.\nЕсли требуется вставить новое число в отсортированный массив, это займёт время ",[1095,7676,1279],{},".\nПроблема здесь в том, чтобы найти место для нового значения.\nПридётся передвинуть несколько элементов, чтобы освободить для него место.\nВот если бы вставку можно было выполнить как в связанном списке, где достаточно поменять пару указателей...\nНо минус связанного списка в том, что поиск выполняется за линейное время ",[1095,7679,1279],{},".\nКак взять и использовать только лучшие стороны обоих решений из массивов и связанных списков?",[566,7682,7684],{"id":7683},"скорость-вставки-в-деревьях","Скорость вставки в деревьях",[554,7686,7687],{},"Нам понадобится структура данных объединяющая идеи вставки и поиска.\nЭта структура называется сбалансированное бинарное дерево поиска (BST).\nBST это разновидность бинарного дерева. Рассмотрим пример:",[554,7689,7690],{},[594,7691],{"alt":7692,"src":7693},"Пример дерева","\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_1.png",[554,7695,7696,7697,7700],{},"Как и в бинарном дереве, каждый узел имеет до двух дочерних узлов: левый и правый.\nНо у этого дерева есть одно свойство, относящее его к BST: ",[1095,7698,7699],{},"значение левого дочернего узла всегда меньше, чем значение узла, а значение правого дочернего узла всегда больше.","\nТаким образом, для корневого узла 10 левый дочерний узел имеет меньшее значение 4, а правый дочерний узел — большее значение 15.\nК тому же, все числа в поддереве левого дочернего узла меньше самого узла!\nЭто особое свойство означает, что поиск будет выполняться очень быстро.",[554,7702,7703],{},"Давайте посмотрим на алгоритм, содержится ли число 6 в этом дереве? Начнём с корневого узла.\nЧисло 6 меньше 10, поэтому проверяем левое поддерево.\nПомните: все узлы с меньшими значениями находятся в левом поддереве, а все узлы с большими значениями — в правом.\nСледовательно, мы сразу понимаем, что проверять узлы справа не нужно, потому что 6 там не будет.\nОпускаясь по левому поддереву от 10, переходим к узлу 4.\nЧисло 6 больше 4, поэтому далее идём направо.\nИ вот мы нашли число 6. Теперь поищем другое число — 8. Поиск происходит аналогично по такому же пути.",[554,7705,7706],{},"Собственно, все рассуждения о деревьях обусловлены одной необходимостью: знать, работают ли они быстрее массивов и связанных списков.\nРассмотрим производительность деревьев, но для этого необходимо учитывать их высоту. Короткие деревья работают быстрее.\nВ лучшем случае высота дерева равна 2. Это означает, что к любому узлу можно перейти от корневого узла максимум за 2 шага.\nВысота дерева для худшего случая с теми же данными будет равна 6.\nЭто означает, что к любому узлу можно перейти от корневого узла максимум за 6 шагов.\nПомните игру с отгадыванием чисел?\nЧтобы угадать число из набора 100 чисел, бинарный поиск потребует максимум 7 попыток, а простому может потребоваться все 100 попыток.\nНечто похожее происходит и с деревьями.",[554,7708,7709,7710,7712,7713,7716,7717],{},"Дерево для худшего случая содержит больше уровней и у него хуже с производительностью.\nВ нём все узлы выстроены в одну линию. Дерево имеет высоту ",[1095,7711,1279],{},", так что поиск будет выполняться за время ",[1095,7714,7715],{},"O(n).","\nПредставить можно так: дерево напоминает связанный список, так как один узел содержит ссылку на другой.\nПоиск по связанному списку выполняется за время ",[1095,7718,7715],{},[554,7720,7721,7722,7724,7725,5986],{},"Дерево для худшего случая имеет высоту ",[1095,7723,1424],{},", а поиск по нему занимает время ",[1095,7726,1424],{},[554,7728,7729,7730,7733,7734,7736,7737,7739,7740,7743],{},"Таким образом, ситуация очень похожа на сравнение бинарного поиска с простым линейным поиском!\nЕсли высота дерева всегда будет обеспечиваться как ",[1095,7731,7732],{},"log n",", то поиск будет выполнятся за время ",[1095,7735,1424],{},".\nНо как добиться, чтобы высота составляла ",[1095,7738,1424],{},"? Кратчайшее время для BST может составлять ",[1095,7741,7742],{},"O(log n).","\nЧтобы этого добиться, нужно сбалансировать дерево. Рассмотрим сбалансированное дерево BST.",[566,7745,7747],{"id":7746},"авл-деревья","АВЛ-деревья",[554,7749,7750,7751,7753,7754,7756],{},"АВЛ-деревья (АВЛ аббревиатура образована от фамилий ученых придумавших эту структуру данных: Адельсон, Вельский, Ландис)\nсоставляют разновидность \"самобалансируемых\" BST.\nЭто означает, что АВЛ-деревья сохраняют высоту ",[1095,7752,1424],{},".\nКаждый раз, когда дерево \"разбалансируется\", то есть его высота становится отличной от O(log n), оно корректирует себя.\nАВЛ-дерево обеспечивает нужную высоту ",[1095,7755,1424],{}," за счёт самобалансировки и поворотов.",[574,7758,7760],{"id":7759},"повороты-авл-дерева","Повороты АВЛ-дерева",[554,7762,7763],{},"Повороты — популярный метод балансировки деревьев. Представьте, что имеется дерево с тремя узлами.\nЛюбой из них может быть корневым. В результате поворота набор узлов смещается, образуя новую конфигурацию.\nНачнем с двух узлов, рассмотрим поворот:",[554,7765,7766],{},[594,7767],{"alt":7768,"src":7769},"Пример АВЛ-дерева","\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_2.png",[554,7771,7772],{},"Высоты дочерних узлов неодинаковы: разность между ними не превышает 1.\nОднако разность в 1 уровень приемлема для АВЛ-деревьев. Теперь добавим ещё один узел.",[554,7774,7775],{},[594,7776],{"alt":7768,"src":7777},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_3.png",[554,7779,7780],{},"Дерево \"разбалансировалось\". Нужно его повернуть.",[554,7782,7783],{},[594,7784],{"alt":7768,"src":7785},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_4.png",[554,7787,7788],{},"Выполнили поворот влево, теперь дерево снова сбалансировано.\nДобавим ещё один узел.",[554,7790,7791],{},[594,7792],{"alt":7768,"src":7793},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_5.png",[554,7795,7796],{},"И ещё один.",[554,7798,7799],{},[594,7800],{"alt":7768,"src":7801},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_6.png",[554,7803,7804],{},"Снова выполним поворот.",[554,7806,7807],{},[594,7808],{"alt":7768,"src":7809},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_7.png",[554,7811,7812],{},"После поворота АВЛ-деревья перебалансируются.\nЗаметим, что в последнем повороте вместо узла 15 поворачивался узел 30. Разберёмся далее почему так.",[574,7814,7816],{"id":7815},"как-авл-дерево-узнает-что-требуется-поворот","Как АВЛ-дерево узнает, что требуется поворот?",[554,7818,7819,7820,7823],{},"Чтобы дерево знало, когда требуется самобалансировка, оно должно хранить дополнительную информацию.\nВ каждом узле хранится один или два вида информации: значение высоты или значение, которое иногда называют ",[1095,7821,7822],{},"коэффициентом балансировки",".\nЭтот коэффициент должен быть равен -1, 0 или 1.",[554,7825,7826],{},[594,7827],{"alt":7828,"src":7829},"Пример АВЛ-деревьев","\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_8.png",[554,7831,7832],{},"Выше на рисунке приведены коэффициенты балансировки только для корневых узлов, но может понадобиться хранить коэффициент балансировки для каждого узла.",[554,7834,7835],{},"Коэффициент балансировки сообщает, какой дочерний узел выше и насколько.\nПо коэффициенту балансировки дерево может определить, когда следует проводить перебалансировку.\nЗначение 0 означает, что дерево сбалансировано.\nСо значениями -1 или 1 все нормально, потому что, АВЛ-деревья не обязаны быть идеально сбалансированы: разность 1 допустима.\nНо если коэффициент балансировки падает ниже -1 или поднимается выше 1, дерево нуждается в перебалансировке.\nНиже пример двух таких деревьев:",[554,7837,7838],{},[594,7839],{"alt":7828,"src":7840},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_9.png",[554,7842,7843],{},"В каждом узле должна храниться либо высота, либо коэффициент балансировки. Можно хранить и то и другое.\nЕсли известны высоты каждого поддерева, то легко вычисляется коэффициент балансировки.\nРассмотрим пример:",[554,7845,7846],{},[594,7847],{"alt":7768,"src":7848},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_10.png",[554,7850,7851],{},"Для начала запишем высоту и коэффициент балансировки для каждого узла.\nНа этой схеме В – высота, а К – коэффициент балансировки.\nХраним в данном примере два значения, но достаточно в реализации хранить только одно.\nУ всех корневых узлов коэффициент балансировки равен 0: у них нет дочерних узлов, поэтому и поддерживать баланс не нужно.\nДобавим в дерево новый узел:",[554,7853,7854],{},[594,7855],{"alt":7768,"src":7856},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_11.png",[554,7858,7859],{},"После того как узел был добавлен, необходимо задать для него высоту и коэффициент балансировки.\nЗатем следует подняться вверх по дереву, обновляя высоты и коэффициенты балансировки для всех его предков.\nПосле вставки нового элемента в дерево — обновляются все коэффициенты балансировки для предков вставленного узла.\nАВЛ-дерево проверяет коэффициент балансировки, чтобы после выполнять перебалансировку.\nВ данном примере выше присутствует коэффициент балансировки -2, это означает что узел в дереве нужно повернуть!\nПовернём узел 10:",[554,7861,7862],{},[594,7863],{"alt":7768,"src":7864},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_12.png",[554,7866,7867],{},"Теперь дерево сбалансировано. Если продолжить движение вверх по дереву то также ничего балансировать уже будет не нужно.\nДвигаться от \"перебалансированного\" узла вверх по дереву необязательно, потому что АВЛ-деревья требуют не более одной \"перебалансировки\".",[554,7869,7870,7871,7873,7874,5986],{},"Итак, АВЛ-деревья хороши, если требуется сбалансированное дерево BST. АВЛ-деревья обеспечивают производительность поиска ",[1095,7872,1424],{},".\nА что со вставкой? Вставка сводится к поиску места для вставки узла и добавления указателя, как в связанном списке.\nНапример, если необходимо вставить элемент в сбалансированное АВЛ-дерево, то необходимо сначала определить, где добавить указатель.\nИ таким образом, вставка тоже выполняется за время ",[1095,7875,1424],{},[554,7877,7878],{},"Получается что структура данных АВЛ-дерево или сбалансированное дерево BST обеспечивает и быструю вставку и быстрый поиск!\nОбщая информация по трём структурам данных в таблице ниже:",[999,7880,7881,7897],{},[1002,7882,7883],{},[1005,7884,7885,7888,7891,7894],{},[1008,7886,7887],{},"-------",[1008,7889,7890],{},"Отсортированный массив",[1008,7892,7893],{},"Связанный список",[1008,7895,7896],{},"АВЛ-дерево",[1015,7898,7899,7910],{},[1005,7900,7901,7904,7906,7908],{},[1020,7902,7903],{},"Поиск",[1020,7905,1424],{},[1020,7907,1279],{},[1020,7909,1424],{},[1005,7911,7912,7915,7917,7919],{},[1020,7913,7914],{},"Вставка",[1020,7916,1279],{},[1020,7918,1327],{},[1020,7920,1424],{},[566,7922,7924],{"id":7923},"косые-деревья","Косые деревья",[554,7926,7927,7928,7930,7931,7933,7934,7936,7937,7939,7940,7942],{},"Косые деревья или Splay-деревья представляют другой подход к сбалансированным деревьям BST.\nИх самое лучшее свойство в том, что если был произведён недавно поиск какого-то элемента, то следующий поиск будет быстрее.\nЭто свойство интуитивно рассматривается положительно.\nПредставьте, что необходимо реализовать работу с программой, которая получает почтовый индекс и находит по нему город.\nИ также представьте, что необходимо многократно каждый раз получать и проводить поиск одного и того же почтового индекса.\nПочему бы не запомнить прошлый результат поиска? Косые деревья позволяют это сделать.\nКогда происходит поиск в косом дереве, он становится после нахождения новым корневым узлом.\nТак при повторном поиске этот же узел будет найден сразу же!\nВ общем случае узлы, которые недавно искали, группируются ближе к корню и находятся быстрее.\nС другой стороны, дерево заведомо не будет сбалансировано, а значит, некоторые операции поиска будут занимать время, большее чем ",[1095,7929,1424],{},", и даже достигать линейного времени!\nКроме того, может потребоваться повернуть узел до корневой позиции, если он ещё некорневой,а это тоже потребует времени.\nНо в целом рассматривая реализацию конкретной задачи, нас должно устраивать, что дерево не будет сбалансировано постоянно.\nГлавное, что при проведении n операций поиска общее время ",[1095,7932,1275],{}," гарантированно — т.е. ",[1095,7935,1424],{}," на один поиск.\nТаким образом, хотя один поиск может занять время, превышающее ",[1095,7938,1424],{},", в среднем все операции поиска сходятся ко времени ",[1095,7941,1424],{},", а цель как раз и есть ускорение поиска.",[566,7944,7946],{"id":7945},"b-деревья","B-деревья",[554,7948,7949],{},"B-деревья представляют собой обобщённую форму бинарных деревьев.\nОни часто используются для построения баз данных.\nНиже представлен пример B-дерева:",[554,7951,7952],{},[594,7953],{"alt":7954,"src":7955},"Пример В-дерева","\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_13.png",[554,7957,7958],{},"Выглядит интересно, правда? Можно заметить, что некоторые узлы имеют более двух дочерних узлов.\nВ отличие от других деревьев поиска (например, двоичного дерева, АВЛ‑дерева),\nгде каждый узел хранит один ключ и максимум двух потомков, в B‑дереве:",[1060,7960,7961,7964],{},[1063,7962,7963],{},"узел может содержать несколько ключей;",[1063,7965,7966],{},"узел может иметь более двух потомков.",[554,7968,7969],{},"B-дерево — это обобщенная форма бинарного дерева поиска.",[574,7971,7973],{"id":7972},"какие-преимущества-есть-у-b-деревьев","Какие преимущества есть у B-деревьев?",[554,7975,7976,7977,7980],{},"Для B-деревьев существует оптимизация, интересная тем, что применяется на физическом уровне.\nПри поиске по дереву получение данных требует перемещения механических компонентов оборудования (например, считывающей головки HDD диска).\nВремя получения данных называется ",[1095,7978,7979],{},"временем поиска",". Оно может быть важным фактором, определяющим, насколько быстро или медленно работает алгоритм.",[554,7982,7983],{},"Ситуация можно сравнить с посещением магазина. Вы можете покупать продукты по одному. Представьте, что вы решаете купить яблоки.\nВернувшись из магазина, вы понимаете, что было бы неплохо купить ещё и апельсины, и возвращаетесь в магазин.\nПо возвращении вы видите, что у вас закончился шоколад, и снова поход в магазин... Это крайне неэффективно!\nНамного лучше зайти в магазин и купить за раз все необходимые товары, находясь в нём.\nВремя похода в магазин и возвращения из него представляет собой время поиска.",[554,7985,7986],{},"Фундаментальная концепция B-деревьев заключается в том, что после выполнения поиска можно прочитать дополнительные данные в память.\nЭто как сходить в магазин и купить сразу всё необходимое чтобы не ходить в него снова.",[554,7988,7989],{},"В B-деревьях используются большие узлы; каждый узел может иметь больше ключей и дочерних узлов, чем бинарное дерево.\nТаким образом, чтение каждого узла займёт больше времени.\nС другой стороны, поиск при больших данных ускоряется, потому что за один раз читается больший объём данных.\nИменно это обстоятельство обеспечивает высокую скорость работы с B-деревом.",[554,7991,7992],{},"Структура B-деревьев популярна в реализациях баз данных.\nИ это не удивительно, ведь в базах данных много времени занимает чтение с дисков.\nКак происходит обход B-дерева? Начинается всё с нижнего крайнего левого или правого узла.\nА дальше змейкой обход остальных узлов.",[554,7994,7995],{},[594,7996],{"alt":7954,"src":7997},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_14.png",[554,7999,8000],{},"Обратите внимание на свойство как у BST деревьев. Для каждого ключа значения ключей в левом поддереве меньше, а значения ключей в правом поддереве — больше него.\nНапример, для ключа 6 левое поддерево состоит из ключей 4 и 5, а правое поддерево из ключей 7 и 8.\nТакже количество дочерних узлов на 1 больше количества ключей. Таким образом, корневой узел имеет один ключ и два дочерних узла.\nКаждый из дочерних узлов имеет два ключа и три дочерних узла.",[554,8002,8003],{},"На этом можно завершить изучение деревьев.\nВам вряд ли придётся реализовывать их самостоятельно, но важно знать, что деревья — это разновидность графов и они обладают отличной производительностью.",[551,8005,8006],{},[554,8007,8008,8009,6828,8012,5986],{},"В следующей статье можно узнать о популярном алгоритме на ",[1095,8010,8011],{},"взвешенных графах",[558,8013,290],{"href":291},[566,8015],{"id":982},[546,8017],{":isList":8018,"title":1208},"[\"Сбалансированные бинарные деревья поиска (BST) обеспечивают такую же производительность в нотации \\\"О-большое\\\", как массивы, и лучшую производительность вставки;\",\"Высота дерева влияет на его производительность;\",\"АВЛ-деревья — популярная разновидность сбалансированных деревьев BST. Как и большинство сбалансированных деревьев, АВЛ-деревья балансируются поворотом;\",\"В-деревья представляют собой обобщенные деревья BST, у которых каждый узел может иметь несколько ключей и несколько дочерний узлов;\",\"Время поиска можно сравнить со временем похода в магазин. В-деревья минимизируют время поиска за счёт чтения большего объёма данных за одну операцию.\"]",{"title":982,"searchDepth":1443,"depth":1444,"links":8020},[8021],{"id":7640,"depth":1443,"text":286,"children":8022},[8023],{"id":7661,"depth":1458,"text":7662,"children":8024},[8025,8026,8030,8031,8034],{"id":7683,"depth":1449,"text":7684},{"id":7746,"depth":1449,"text":7747,"children":8027},[8028,8029],{"id":7759,"depth":1444,"text":7760},{"id":7815,"depth":1444,"text":7816},{"id":7923,"depth":1449,"text":7924},{"id":7945,"depth":1449,"text":7946,"children":8032},[8033],{"id":7972,"depth":1444,"text":7973},{"id":982,"depth":1449,"text":982},"2026-03-18","Бинарное дерево поиска. Сбалансированные деревья. АВЛ-деревья. B-деревья.","images\u002Fblog\u002Fpython\u002Fst31\u002Fimg.png",{},{"title":286,"description":8036},"Xx7RmQRNESHyB_B1uir7IBoU0Gwk7D2VamQNbVZ_qK4",1780737498340]