Визначення відстані між двома паралельними прямими. А ви знаєте, чому по прямій далі, ніж по дузі? Що таке найкоротша відстань між двома точками

Наметове крейдою дві точки на класній дошці, вчителька пропонує юному школяреві завдання: накреслити найкоротший шлях між обома точками.

Учень, подумавши, старанно виводить між ними звивисту лінію.

- Ось так найкоротший шлях! - дивується вчителька. - Хто тебе так навчив?

- Мій тато. Він шофер таксі.

Креслення наївного школяра, звичайно, анекдотічен, але хіба не посміхнулися б ви, якби вам сказали, що пунктирна дуга на рис. 1 - найкоротший шлях від мису Доброї Надії до південного краю Австралії!

Ще більш вражаючим наступне твердження: зображений на рис. 2 кружним шлях з Японії до Панамського каналу коротше прямій лінії, проведеної між ними на тій же карті!

Мал. 1. На морській карті найкоротший шлях від мису Доброї Надії до південного краю Австралії позначається не прямий лінією ( «локсодромії»), а кривої ( «ортодромії»)


Все це схоже на жарт, а тим часом перед вами - безперечні істини, добре відомі картографам.




Мал. 2. Здається неймовірним, що криволінійний шлях, що з'єднує на морській карті Йокогаму з Панамським каналом, коротше прямій лінії, проведеної між тими ж точками


Для роз'яснення питання доведеться сказати кілька слів про картах взагалі і про морські зокрема. Зображення на папері частин земної поверхні - справа непроста навіть в принципі, тому що Земля - \u200b\u200bкуля, а відомо, що ніяку частину кульової поверхні не можна розгорнути на площині без складок і розривів. Мимоволі доводиться миритися з неминучими спотвореннями на картах. Придумано багато способів креслення карт, але всі карти не вільні від недоліків: на одних є спотворення одного роду, на інших іншого роду, але карт зовсім без спотворень немає.

Моряки користуються картами, накреслені за способом старовинного голландського картографа і математика XVI в. Меркатора. Спосіб цей називається «меркаторской проекцією». Дізнатися морську карту легко по її прямокутної сітці: меридіани зображені на ній у вигляді ряду паралельних прямих ліній; кола широти - теж прямими лініями, перпендикулярними до перших (див. рис. 5).

Уявіть тепер, що потрібно знайти найкоротший шлях від одного океанського порту до іншого, що лежить на тій же паралелі. На океані все шляху доступні, і здійснити там подорож по найкоротшому шляху завжди можливо, якщо знати, як він пролягає. У нашому випадку природно думати, що найкоротший шлях йде уздовж тієї паралелі, на якій лежать обидва порту: адже на карті - це пряма лінія, а що може бути коротше прямого шляху! Але ми помиляємося: шлях по паралелі зовсім не найкоротший.

Справді: на поверхні кулі найкоротша відстань між двома точками є з'єднує їх дуга великого кола. Але коло паралелі - малий коло. Дуга великого кола менш викривлена, ніж дуга будь-якого малого кола, проведеного через ті ж дві точки: більшого радіусу відповідає менша кривизна. Натягніть на глобусі нитка між нашими двома точками (пор. Рис. 3); ви переконаєтеся, що вона зовсім не ляже вздовж паралелі. Натягнута нитка - безперечний покажчик найкоротшого шляху, а якщо вона на глобусі не збігається з паралеллю, то і на морській карті найкоротший шлях не позначається прямою лінією: згадаймо, що кола паралелей зображуються на такій карті прямими лініями, всяка ж лінія, не збігається з прямою , є крива .



Мал. 3. Простий спосіб відшукання дійсно найкоротшого шляху між двома пунктами: треба на глобусі натягнути нитку між цими пунктами


Після сказаного стає зрозумілим, чому найкоротший шлях на морській карті зображується не прямою, а кривою лінією.

Розповідають, що при виборі напрямку для Миколаївській (нині Жовтневої) залізниці велися нескінченні суперечки про те, яким шляхом її прокласти. Край суперечкам поклало втручання царя Миколи I, який вирішив задачу буквально «прямолінійно»: поєднав Петербург з Москвою по лінійці. Якби це було зроблено на меркаторской карті, вийшла б конфузно несподіванка: замість прямої дорога вийшла б кривої.

Хто не уникає розрахунків, той нескладним обчисленням може переконатися, що шлях, який здається нам на карті кривих, в дійсності коротше того, який ми готові вважати прямим. Нехай обидві наші гавані лежать на 60-й паралелі і розділені відстанню в 60 °. (Чи існують в дійсності такі дві гавані - для розрахунку, звичайно, байдуже.)



Мал. 4. До обчислення відстаней між точками А і В на кулі по дузі паралелі і по дузі великого кола


На рис. 4 точка Про -центр земної кулі, АВ -дуга кола широти, на якому лежать гавані А та В; вній 60 °. Центр кола широти - в точці ЗУявімо, що з центру Проземної кулі проведена через ті ж гавані дуга великого кола: її радіус OB \u003d ОА \u003d R;вона пройде близько до накресленої дузі АВ,але не співпаде з нею.

Обчислимо довжину кожної дуги. Так як точки Аі Влежать на широті 60 °, то радіуси ОАі ОВскладають з ОС(Віссю земної кулі) кут в 30 °. У прямокутному трикутнику АСОкатет АС (\u003d r),що лежить проти кута в 30 °, дорівнює половині гіпотенузи АТ;

значить, r \u003d R / 2 довжина дуги АВстановить одну шосту довжини кола широти, а так як це коло має вдвічі меншу довжину, ніж велике коло (відповідно вдвічі меншому радіусу), то довжина дуги малого кола



Щоб визначити тепер довжину дуги великого кола, проведеного між тими ж точками (т. Е. Найкоротшого шляху між ними), треба дізнатися величину кута АОВ.хорда AS, Стягуюча дугу в 60 ° (малого кола), є сторона правильного шестикутника, вписаного го в той же мале коло; тому АВ \u003d r \u003d R / 2

провівши пряму OD,сполучає центр Проземної кулі з серединою Dхорди АВ,отримуємо прямокутний трикутник ODA,де кут D -прямий:

DA \u003d 1/2 AB і OA \u003d R.

sinAOD \u003d AD: AO \u003d R / 4: R \u003d 0,25

Звідси знаходимо (за таблицями):

\u003d 14 ° 28 ", 5

і, отже,

\u003d 28 ° 57 ".

Тепер уже неважко знайти шукану довжину найкоротшого шляху в кілометрах. Розрахунок можна спростити, якщо згадати, що довжина хвилини великого кола земної кулі є мо

Ми дізнаємося, що шлях по колу широти, зображений на морській карті прямою лінією, становить 3333 км, а шлях по великому колу - по кривій на карті - 3213 км, т. Е. На 120 км коротше.

Озброївшись ниткою і маючи під руками глобус, ви легко можете перевірити правильність наших креслень і переконатися, що дуги великих кіл дійсно пролягають так, як показано на кресленнях. Зображений на рис. 1 нібито «прямої» морський шлях з Африки до Австралії становить 6020 миль, а «кривий» - 5450 миль, т. Е. Коротше на 570 миль, або на 1050 км. «Прямий» на морській карті повітряний шлях з Лондона в Шанхай перерізає Каспійське море, між тим як дійсно найкоротший шлях пролягає на північ від Петербурга. Зрозуміло, яку роль відіграють ці питання в економії часу і пального.

Якщо в епоху парусного судноплавства не завжди дорожили часом, - тоді «час» ще не вважалося «грошима», - то з появою парових судів доводиться платити за кожну надмірно витрачену тонну вугілля. Ось чому в наші дні ведуть суду по дійсно найкоротшому шляху, користуючись нерідко картами, виконаними не в меркаторской, а в так званій «центральної» проекції: на цих картах дуги великих кіл зображуються прямими лініями.

Чому ж колишні мореплавці користувалися настільки оманливими картами і обирали невигідні шляху? Помилково думати, що за старих часів не знали про зараз зазначеної особливості морських карт. Справа пояснюється, звичайно, не цим, а тим, що карти, накреслені за способом Меркатора, мають поряд з незручностями вельми цінними для моряків вигодами. Така карта, по-перше, зображує окремі невеликі частини земної поверхні без спотворення, зберігаючи кути контуру. Цьому не суперечить те, що з віддаленням від екватора все контури помітно розтягуються. У високих широтах розтягнення так значно, що морська карта вселяє людині, незнайомому з її особливостями, абсолютно хибне уявлення про справжню величиною материків: Гренландія здається такою ж величини, як Африка, Аляска більше Австралії, хоча Гренландія в 15 разів менше Африки, а Аляска разом з Гренландією вдвічі менше Австралії. Але моряка, добре знайомого з цими особливостями карти, вони не можуть ввести в оману. Він мириться з ними, тим більше, що в межах невеликих ділянок морська карта дає точну копію натури (рис. 5).

Зате морська карта вельми полегшує вирішення завдань штурманської практики. Це - єдиний рід карт, на яких шлях корабля, що йде постійним курсом, зображується прямою лінією. Йти «постійним курсом» - значить триматися незмінно одного напрямку, одного певного «румба», інакше кажучи, йти так, щоб перетинати всі меридіани під рівним кутом. Але цей шлях ( «локсодроми») може зобразитися прямою лінією тільки на такій карті, на якій всі меридіани - прямі лінії, паралельні один одному. А так як на земній кулі кола широти перетинаються з меридіанами під прямими кутами, то на такій карті та кола широти повинні бути прямими лініями, перпендикулярними до ліній меридіанів. Коротше кажучи, ми приходимо саме до тієї координатної сітки, яка становить характерну особливість морської карти.




Мал. 5. Морська або меркаторская карта земної кулі. На подібних картах сильно перебільшені розміри контурів, віддалених від екватора. Що, наприклад, більше: Гренландія або Австралія? (Відповідь в тексті)


Пристрасть моряків до карт Меркатора тепер зрозуміло. Бажаючи визначити курс, якого треба триматися, йдучи до призначеного порту, штурман прикладає лінійку до кінцевих точок шляху і вимірює кут, що складається нею з меридіанами. Тримаючись у відкритому морі весь час цього напрямку, штурман безпомилково доведе судно до мети. Ви бачите, що «локсодроми» - хоча і не самий короткий і не найекономніший, але зате у відомому сенсі дуже зручний для моряка шлях. Щоб дійти, наприклад, від мису Доброї Надії до південного краю Австралії (див. Рис. 1), треба незмінно триматися одного курсу S 87 °, 50 ". Між тим, щоб довести судно до того ж кінцевого пункту найкоротшим шляхом (по« ортодромії »), доводиться, як видно з малюнка, безперервно змінювати курс судна: почати з курсу S 42 °, 50", а закінчити курсом N 53 °, 50 "(в цьому випадку найкоротший шлях навіть і неможливий - він впирається в крижану стіну Антарктики ).

Обидва шляхи - по «локсодромії» і по «ортодромії» - збігаються тільки тоді, коли шлях по великому колу зображується на морській карті прямою лінією: при русі по екватору або по меридіану. У всіх інших випадках шляху ці різні.

(Нарисна геометрія)
  • CD (CXDX, C2D2) зображується у вигляді точки С5 \u003d D5 А5В5 одно ...
    (Нарисна геометрія)
  • Визначення відстані між двома паралельними площинами
    Визначення відстані між двома паралельними площинами загального положення 01 | X зручно звести до задачі по визначенню відстані між тими ж двома площинами, перетвореними в положення проектують. У цьому випадку відстань між площинами визначиться як перпендикуляр між прямими, ...
    (Нарисна геометрія)
  • Визначення відстані між двома перехресними прямими
    Якщо потрібно визначити найкоротша відстань між двома перехресними прямими, доводиться двічі змінювати системи площин проекцій. При вирішенні цього завдання пряма CD (CXDX, C2D2) зображується у вигляді точки С5 \u003d D5 (Рис. 198). Відстань від цієї точки до проекції А5В5 одно ...
    (Нарисна геометрія)
  • Кут між двома перехресними прямими лініями
    Це кут між двома пересічними прямими, паралельними даними. Таким чином, ця задача аналогічна попередній. Для її вирішення потрібно взяти довільну точку і через неї провести дві прямі, паралельні заданим перехресних прямих, і за допомогою перетворення проекцій визначити шуканий кут ....
    (Основи нарисної геометрії. Короткий курс і збірник задач.)
  • Визначення відстані між двома паралельними прямими
    Завдання вирішується способом подвійної заміни площин проекцій. На заключному етапі одна з площин проекцій повинна бути перпендикулярна до однієї з перехресних прямих. Тоді найкоротша відстань між ними визначається величиною відрізка перпендикуляра до іншої скрещивающейся прямий (рис. 199) ....
    (Нарисна геометрія)
  • ВІДСТАНЬ, відстані, пор. 1. Простір, що розділяє два пункти, проміжок між чим небудь. Найкоротша відстань між двома точками по прямій. Живе від нас на відстані двох кілометрів. «Комендант підпустив їх на найближчу відстань ... Тлумачний словник Ушакова

    відстань - ім., С., Употр. часто Морфологія: (немає) чого? відстані, чому? віддалі, (бачу) що? відстань, ніж? відстанню, про що? про відстані; мн. що? відстані, (немає) чого? відстаней, чому? відстаням, (бачу) що? відстані, ніж? відстанями ... Тлумачний словник Дмитрієва

    відстань - я; пор. Простір, що розділяє два пункти, два предмета і т.п., проміжок між ким, ніж л. Найкоротша р. між двома точками. Р. від будинку до школи. Відійти на близьке р. На відстані метра, витягнутої руки. Знати що л., Відчувати що л. на ... ... енциклопедичний словник

    відстань - я; пор. см. тж. расстояньіце а) Простір, що розділяє два пункти, два предмета і т.п., проміжок між ким, ніж л. Найкоротша расстоя / ня між двома точками. Расстоя / ня від будинку до школи. Відійти на близьке расстоя / ня ... Словник багатьох виразів

    ГЕОМЕТРІЯ - розділ математики, що займається вивченням властивостей різних фігур (точок, ліній, кутів, двовимірних і тривимірних об'єктів), їх розмірів і взаємного розташування. Для зручності викладання геометрію підрозділяють на планиметрию і стереометрию. В ... ... Енциклопедія Кольєра

    Навігація *

    Навігація - відділ кораблеводіння (див.), Що містить виклад способів визначення місця корабля на морі, користуючись компасом і лагом (див.). Визначити місце корабля на морі, значить нанести на карту ту точку, в якій корабель в даний момент знаходиться. ... ... Енциклопедичний словник Ф.А. Брокгауза і І.А. Ефрона

    Коген - (Cohen) Герман (1842 1918) німецький філософ, засновник і найвидатніший представник Марбурзького школи неокантіанства. Основні роботи: 'Теорія досвіду Канта' (1885), 'Обгрунтування Кантом етики' (1877), 'Обгрунтування Кантом естетики' (1889), 'Логіка ... ...

    Кант Іммануїл - Життєвий шлях і твори Канта Іммануїл Кант народився в Кенігсберзі (нині Калінінград) в Східній Пруссії в 1724 р Батько був шорником, а мати домогосподаркою, шестеро їхніх дітей не дожили до зрілого віку. Кант завжди згадував батьків з ... ... Західна філософія від витоків до наших днів

    КРИТИЧНА ФІЛОСОФІЯ КАНТА: вчення про ЗДІБНОСТЯХ - (La philosophie critique de Kant: Doctrines des facultes, 1963) робота Дельоза. Характеризуючи у введенні трансцендентальний метод, Дельоз фіксує, що Кант розуміє філософію як науку про відношення будь-якого знання до суттєвих цілей ... ... Історія Філософії: Енциклопедія

    ферма принцип - основний принцип геометричної оптики (Див. Геометрична оптика). Найпростіша форма Ф. п. - твердження, що промінь світла завжди поширюється в просторі між двома точками по тому шляху, по якому час його проходження менше, ніж ... Велика Радянська Енциклопедія

    Алгоритм Дейкстри (англ. Dijkstra's algorithm) - алгоритм на графах, винайдений нідерландським вченим Едсгер Дейкстрой в 1959 році. Знаходить найкоротші шляхи від однієї з вершин графа до всіх інших. алгоритм працює тільки для графів без ребер негативного ваги.

    Розглянемо виконання алгоритму на прикладі графа, показаного на малюнку.

    Нехай потрібно знайти найкоротший відстані від 1-ї вершини до всіх інших.

    Гуртками позначені вершини, лініями - шляху між ними (ребра графа). У гуртках позначені номери вершин, над ребрами позначена їх «ціна» - довжина шляху. Поряд з кожною вершиною червоним позначена мітка - довжина найкоротшого шляху в цю вершину з вершини 1.

    Перший крок. Розглянемо крок алгоритму Дейкстри для нашого прикладу. Мінімальну мітку має вершина 1. Її сусідами є вершини 2, 3 і 6.

    Перший по черзі сусід вершини 1 - вершина 2, тому що довжина шляху до неї мінімальна. Довжина шляху в неї через вершину 1 дорівнює сумі значення мітки вершини 1 і довжини ребра, що йде з 1-й в 2-ю, тобто 0 + 7 \u003d 7. Це менше поточної мітки вершини 2, нескінченності, тому нова мітка 2-й вершини дорівнює 7.

    Аналогічну операцію проробляємо з двома іншими сусідами 1-й вершини - 3-й і 6-й.

    Всі сусіди вершини 1 перевірені. Поточне мінімальна відстань до вершини 1 вважається остаточним і перегляду не підлягає (те, що це дійсно так, вперше довів Е. Дейкстра). Викреслимо її з графа, щоб відзначити, що ця вершина переглянуло.

    другий крок. Крок алгоритму повторюється. Знову знаходимо «найближчу» з невідвіданих вершин. Це вершина 2 з міткою 7.

    Знову намагаємося зменшити мітки сусідів обраної вершини, намагаючись пройти в них через 2-ю вершину. Сусідами вершини 2 є вершини 1, 3 і 4.

    Перший (по порядку) сусід вершини 2 - вершина 1. Але вона вже переглянуло, тому з 1-й вершиною нічого не робимо.

    Наступний сусід вершини 2 - вершина 3, так як має мінімальну позначку з вершин, позначених що не відвідані. Якщо йти в неї через 2, то довжина такого шляху буде дорівнює 17 (7 + 10 \u003d 17). Але поточна мітка третьої вершини дорівнює 9, а це менше 17, тому мітка не змінюється.

    Ще один сусід вершини 2 - вершина 4. Якщо йти в неї через 2-ю, то довжина такого шляху буде дорівнює сумі найкоротшої відстані до 2-ї вершини і відстані між вершинами 2 і 4, тобто 22 (7 + 15 \u003d 22) . оскільки 22<, устанавливаем метку вершины 4 равной 22.

    Всі сусіди вершини 2 переглянуті, заморожуємо відстань до неї і помічаємо її як відвіданих.

    третій крок. Повторюємо крок алгоритму, вибравши вершину 3. Після її «обробки» отримаємо такі результати:

    подальші кроки. Повторюємо крок алгоритму для решти вершин. Це будуть вершини 6, 4 і 5, відповідно до порядку.

    Завершення виконання алгоритму. Алгоритм закінчує роботу, коли не можна більше обробити жодної вершини. В даному прикладі всі вершини закреслено, проте помилково вважати, що так буде в будь-якому прикладі - деякі вершини можуть залишитися незачёркнутимі, якщо до них не можна дістатися, т. Е. Якщо граф незв'язних. Результат роботи алгоритму видно на останньому малюнку: найкоротший шлях від вершини 1 до 2-ї становить 7, до 3-й - 9, до 4-ї - 20, до 5-ї - 20, до 6-ї - 11.

    Реалізація алгоритму на різних мовах програмування:

    C ++

    #include "stdafx.h" #include using namespace std; const int V \u003d 6; // алгоритм Дейкстри void Dijkstra (int GR [V] [V], int st) (int distance [V], count, index, i, u, m \u003d st + 1; bool visited [V]; for (i \u003d 0; i "< "<\u003e "; Cin \u003e\u003e start; Dijkstra (GR, start-1); system (" pause \u003e\u003e void ");)

    Pascal

    program DijkstraAlgorithm; uses crt; const V \u003d 6; inf \u003d 100000; type vektor \u003d array of integer; var start: integer; const GR: array of integer \u003d ((0, 1, 4, 0, 2, 0), (0, 0, 0, 9, 0, 0), (4, 0, 0, 7, 0, 0), (0, 9, 7, 0, 0, 2), (0, 0, 0, 0, 0, 8), (0, 0, 0, 0, 0, 0)); (Алгоритм Дейкстри) procedure Dijkstra (GR: array of integer; st: integer); var count, index, i, u, m, min: integer; distance: vektor; visited: array of boolean; begin m: \u003d st; for i: \u003d 1 to V do begin distance [i]: \u003d inf; visited [i]: \u003d false; end; distance: \u003d 0; for count: \u003d 1 to V-1 do begin min: \u003d inf; for i: \u003d 1 to V do if (not visited [i]) and (distance [i]<=min) then begin min:=distance[i]; index:=i; end; u:=index; visited[u]:=true; for i:=1 to V do if (not visited[i]) and (GR<>0) and (distance [u]<>inf) and (distance [u] + GR inf then writeln (m, "\u003e", i, "\u003d", distance [i]) else writeln (m, "\u003e", i, "\u003d", "маршрут недоступний"); end; (Основний блок програми) begin clrscr; write ( "Початкова вершина \u003e\u003e"); read (start); Dijkstra (GR, start); end.

    Java

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.StringTokenizer; public class Solution (private static int INF \u003d Integer.MAX_VALUE / 2; private int n; // кількість вершин в орграфе private int m; // кількість дуг в Орграф private ArrayList adj; // список суміжності private ArrayList weight; // вагу ребра в орграфе private boolean used; // масив для зберігання інформації про пройдені і не пройдених вершинах private int dist; // масив для зберігання відстані від стартової вершини // масив предків, необхідних для відновлення найкоротшого шляху з стартовою вершини private int pred; int start; // стартова вершина, від якої шукається відстань до всіх інших private BufferedReader cin; private PrintWriter cout; private StringTokenizer tokenizer; // процедура запуску алгоритму Дейкстри з стартовою вершини private void dejkstra (int s) (dist [s] \u003d 0; // найкоротша відстань до стартової вершини дорівнює 0 for (int iter \u003d 0; iter< n; ++iter) { int v = -1; int distV = INF; //выбираем вершину, кратчайшее расстояние до которого еще не найдено for (int i = 0; i < n; ++i) { if (used[i]) { continue; } if (distV < dist[i]) { continue; } v = i; distV = dist[i]; } //рассматриваем все дуги, исходящие из найденной вершины for (int i = 0; i < adj[v].size(); ++i) { int u = adj[v].get(i); int weightU = weight[v].get(i); //релаксация вершины if (dist[v] + weightU < dist[u]) { dist[u] = dist[v] + weightU; pred[u] = v; } } //помечаем вершину v просмотренной, до нее найдено кратчайшее расстояние used[v] = true; } } //процедура считывания входных данных с консоли private void readData() throws IOException { cin = new BufferedReader(new InputStreamReader(System.in)); cout = new PrintWriter(System.out); tokenizer = new StringTokenizer(cin.readLine()); n = Integer.parseInt(tokenizer.nextToken()); //считываем количество вершин графа m = Integer.parseInt(tokenizer.nextToken()); //считываем количество ребер графа start = Integer.parseInt(tokenizer.nextToken()) - 1; //инициализируем списка смежности графа размерности n adj = new ArrayList[n]; for (int i = 0; i < n; ++i) { adj[i] = new ArrayList(); ) // ініціалізація списку, в якому зберігаються ваги ребер weight \u003d new ArrayList [n]; for (int i \u003d 0; i< n; ++i) { weight[i] = new ArrayList(); ) // зчитуємо граф, заданий списком ребер for (int i \u003d 0; i< m; ++i) { tokenizer = new StringTokenizer(cin.readLine()); int u = Integer.parseInt(tokenizer.nextToken()); int v = Integer.parseInt(tokenizer.nextToken()); int w = Integer.parseInt(tokenizer.nextToken()); u--; v--; adj[u].add(v); weight[u].add(w); } used = new boolean[n]; Arrays.fill(used, false); pred = new int[n]; Arrays.fill(pred, -1); dist = new int[n]; Arrays.fill(dist, INF); } //процедура восстановления кратчайшего пути по массиву предком void printWay(int v) { if (v == -1) { return; } printWay(pred[v]); cout.print((v + 1) + " "); } //процедура вывода данных в консоль private void printData() throws IOException { for (int v = 0; v < n; ++v) { if (dist[v] != INF) { cout.print(dist[v] + " "); } else { cout.print("-1 "); } } cout.println(); for (int v = 0; v < n; ++v) { cout.print((v + 1) + ": "); if (dist[v] != INF) { printWay(v); } cout.println(); } cin.close(); cout.close(); } private void run() throws IOException { readData(); dejkstra(start); printData(); cin.close(); cout.close(); } public static void main(String args) throws IOException { Solution solution = new Solution(); solution.run(); } }

    Ще один варіант:

    Import java.io. *; import java.util. *; public class Dijkstra (private static final Graph.Edge GRAPH \u003d (new Graph.Edge ( "a", "b", 7), new Graph.Edge ( "a", "c", 9), new Graph.Edge ( "a", "f", 14), new Graph.Edge ( "b", "c", 10), new Graph.Edge ( "b", "d", 15), new Graph.Edge ( "c "," d ", 11), new Graph.Edge (" c "," f ", 2), new Graph.Edge (" d "," e ", 6), new Graph.Edge (" e ", "f", 9),); private static final String START \u003d "a"; private static final String END \u003d "e"; public static void main (String args) (Graph g \u003d new Graph (GRAPH); g.dijkstra (START); g.printPath (END); //g.printAllPaths ();)) class Graph (private final Map graph; // mapping of vertex names to Vertex objects, built from a set of Edges / ** One edge of the graph (only used by Graph constructor) * / public static class Edge (public final String v1, v2; public final int dist; public Edge (String v1, String v2, int dist) (this.v1 \u003d v1; this.v2 \u003d v2; this.dist \u003d dist;)) / ** One vertex of the graph, complete with mappings to neighbouring vertices * / public static class Vertex implements Comparable (Public final String name; public int dist \u003d Integer.MAX_VALUE; // MAX_VALUE assumed to be infinity public Vertex previous \u003d null; public final Map neighbours \u003d new HashMap<>(); public Vertex (String name) (this.name \u003d name;) private void printPath () (if (this \u003d\u003d this.previous) (System.out.printf ( "% s", this.name);) else if ( this.previous \u003d\u003d null) (System.out.printf ( "% s (unreached)", this.name);) else (this.previous.printPath (); System.out.printf ( "-\u003e% s ( % d) ", this.name, this.dist);)) public int compareTo (Vertex other) (return Integer.compare (dist, other.dist);)) / ** Builds a graph from a set of edges * / public Graph (Edge edges) (graph \u003d new HashMap<>(Edges.length); // one pass to find all vertices for (Edge e: edges) (if (! Graph.containsKey (e.v1)) graph.put (e.v1, new Vertex (e.v1)); if (! Graph. containsKey (e.v2)) graph.put (e.v2, new Vertex (e.v2));) // another pass to set neighbouring vertices for (Edge e: edges) (graph.get (e.v1). neighbours.put (graph.get (e.v2), e.dist); //graph.get(e.v2).neighbours.put(graph.get(e.v1), e.dist); // also do this for an undirected graph)) / ** Runs dijkstra using a specified source vertex * / public void dijkstra (String startName) (if (! graph.containsKey (startName)) (System.err.printf ( "Graph doesn" t contain start vertex \\ "% s \\" \\ n ", startName); return;) final Vertex source \u003d graph.get (startName); NavigableSet q \u003d new TreeSet<>(); // set-up vertices for (Vertex v: graph.values \u200b\u200b()) (v.previous \u003d v \u003d\u003d source? Source: null; v.dist \u003d v \u003d\u003d source? 0: Integer.MAX_VALUE; q.add ( v);) dijkstra (q); ) / ** Implementation of dijkstra "s algorithm using a binary heap. * / Private void dijkstra (final NavigableSet q) (Vertex u, v; while (! q.isEmpty ()) (u \u003d q.pollFirst (); // vertex with shortest distance (first iteration will return source) if (u.dist \u003d\u003d Integer.MAX_VALUE) break; // we can ignore u (and any other remaining vertices) since they are unreachable // look at distances to each neighbour for (Map.Entry a: u.neighbours.entrySet ()) (v \u003d a.getKey (); // the neighbour in this iteration final int alternateDist \u003d u.dist + a.getValue (); if (alternateDist< v.dist) { // shorter path to neighbour found q.remove(v); v.dist = alternateDist; v.previous = u; q.add(v); } } } } /** Prints a path from the source to the specified vertex */ public void printPath(String endName) { if (!graph.containsKey(endName)) { System.err.printf("Graph doesn"t contain end vertex \"%s\"\n", endName); return; } graph.get(endName).printPath(); System.out.println(); } /** Prints the path from the source to every vertex (output order is not guaranteed) */ public void printAllPaths() { for (Vertex v: graph.values()) { v.printPath(); System.out.println(); } } }

    C

    #include #include #include // # define BIG_EXAMPLE typedef struct node_t node_t, * heap_t; typedef struct edge_t edge_t; struct edge_t (node_t * nd; / * target of this edge * / edge_t * sibling; / * for singly linked list * / int len; / * edge cost * /); struct node_t (edge_t * edge; / * singly linked list of edges * / node_t * via; / * where previous node is in shortest path * / double dist; / * distance from origining node * / char name; / * the, er , name * / int heap_idx; / * link to heap position for updating distance * /); / * --- edge management --- * / #ifdef BIG_EXAMPLE # define BLOCK_SIZE (1024 * 32 - 1) #else # define BLOCK_SIZE 15 #endif edge_t * edge_root \u003d 0, * e_next \u003d 0; / * Don "t mind the memory management stuff, they are besides the point. Pretend e_next \u003d malloc (sizeof (edge_t)) * / void add_edge (node_t * a, node_t * b, double d) (if (e_next \u003d\u003d edge_root ) (edge_root \u003d malloc (sizeof (edge_t) * (BLOCK_SIZE + 1)); edge_root.sibling \u003d e_next; e_next \u003d edge_root + BLOCK_SIZE;) --e_next; e_next-\u003e nd \u003d b; e_next-\u003e len \u003d d; e_next -\u003e sibling \u003d a-\u003e edge; a-\u003e edge \u003d e_next;) void free_edges () (for (; edge_root; edge_root \u003d e_next) (e_next \u003d edge_root.sibling; free (edge_root);)) / * --- priority queue stuff --- * / heap_t * heap; int heap_len; void set_dist (node_t * nd, node_t * via, double d) (int i, j; / * already knew better path * / if (nd-\u003e via && d\u003e \u003d nd-\u003e dist) return; / * find existing heap entry, or create a new one * / nd-\u003e dist \u003d d; nd-\u003e via \u003d via; i \u003d nd-\u003e heap_idx; if (! i) i \u003d ++ heap_len; / * upheap * / for (; i\u003e 1 && nd-\u003e dist< heap->dist; i \u003d j) (heap [i] \u003d heap [j]) -\u003e heap_idx \u003d i; heap [i] \u003d nd; nd-\u003e heap_idx \u003d i; ) Node_t * pop_queue () (node_t * nd, * tmp; int i, j; if (! Heap_len) return 0; / * remove leading element, pull tail element there and downheap * / nd \u003d heap; tmp \u003d heap; for (i \u003d 1; i< heap_len && (j = i * 2) <= heap_len; i = j) { if (j < heap_len && heap[j]->dist\u003e heap-\u003e dist) j ++; if (heap [j] -\u003e dist\u003e \u003d tmp-\u003e dist) break; (Heap [i] \u003d heap [j]) -\u003e heap_idx \u003d i; ) Heap [i] \u003d tmp; tmp-\u003e heap_idx \u003d i; return nd; ) / * --- Dijkstra stuff; unreachable nodes will never make into the queue --- * / void calc_all (node_t * start) (node_t * lead; edge_t * e; set_dist (start, start, 0); while ((lead \u003d pop_queue ())) for ( e \u003d lead-\u003e edge; e; e \u003d e-\u003e sibling) set_dist (e-\u003e nd, lead, lead-\u003e dist + e-\u003e len);) void show_path (node_t * nd) (if (nd-\u003e via \u003d\u003d nd) printf ( "% s", nd-\u003e name); else if (! nd-\u003e via) printf ( "% s (unreached)", nd-\u003e name); else (show_path (nd-\u003e via); printf ( "-\u003e% s (% g)", nd-\u003e name, nd-\u003e dist);)) int main (void) (#ifndef BIG_EXAMPLE int i; # define N_NODES ( "f" - " a "+ 1) node_t * nodes \u003d calloc (sizeof (node_t), N_NODES); for (i \u003d 0; i< N_NODES; i++) sprintf(nodes[i].name, "%c", "a" + i); # define E(a, b, c) add_edge(nodes + (a - "a"), nodes + (b - "a"), c) E("a", "b", 7); E("a", "c", 9); E("a", "f", 14); E("b", "c", 10);E("b", "d", 15);E("c", "d", 11); E("c", "f", 2); E("d", "e", 6); E("e", "f", 9); # undef E #else /* BIG_EXAMPLE */ int i, j, c; # define N_NODES 4000 node_t *nodes = calloc(sizeof(node_t), N_NODES); for (i = 0; i < N_NODES; i++) sprintf(nodes[i].name, "%d", i + 1); /* given any pair of nodes, there"s about 50% chance they are not connected; if connected, the cost is randomly chosen between 0 and 49 (inclusive! see output for consequences) */ for (i = 0; i < N_NODES; i++) { for (j = 0; j < N_NODES; j++) { /* majority of runtime is actually spent here */ if (i == j) continue; c = rand() % 100; if (c < 50) continue; add_edge(nodes + i, nodes + j, c - 50); } } #endif heap = calloc(sizeof(heap_t), N_NODES + 1); heap_len = 0; calc_all(nodes); for (i = 0; i < N_NODES; i++) { show_path(nodes + i); putchar("\n"); } #if 0 /* real programmers don"t free memories (they use Fortran) */ free_edges(); free(heap); free(nodes); #endif return 0; }

    PHP

    $ Edge, "cost" \u003d\u003e $ edge); $ Neighbours [$ edge] \u003d array ( "end" \u003d\u003e $ edge, "cost" \u003d\u003e $ edge); ) $ Vertices \u003d array_unique ($ vertices); foreach ($ vertices as $ vertex) ($ dist [$ vertex] \u003d INF; $ previous [$ vertex] \u003d NULL;) $ dist [$ source] \u003d 0; $ Q \u003d $ vertices; while (count ($ Q)\u003e 0) (// TODO - Find faster way to get minimum $ min \u003d INF; foreach ($ Q as $ vertex) (if ($ dist [$ vertex]< $min) { $min = $dist[$vertex]; $u = $vertex; } } $Q = array_diff($Q, array($u)); if ($dist[$u] == INF or $u == $target) { break; } if (isset($neighbours[$u])) { foreach ($neighbours[$u] as $arr) { $alt = $dist[$u] + $arr["cost"]; if ($alt < $dist[$arr["end"]]) { $dist[$arr["end"]] = $alt; $previous[$arr["end"]] = $u; } } } } $path = array(); $u = $target; while (isset($previous[$u])) { array_unshift($path, $u); $u = $previous[$u]; } array_unshift($path, $u); return $path; } $graph_array = array(array("a", "b", 7), array("a", "c", 9), array("a", "f", 14), array("b", "c", 10), array("b", "d", 15), array("c", "d", 11), array("c", "f", 2), array("d", "e", 6), array("e", "f", 9)); $path = dijkstra($graph_array, "a", "e"); echo "path is: ".implode(", ", $path)."\n";


    Python

    from collections import namedtuple, queue from pprint import pprint as pp inf \u003d float ( "inf") Edge \u003d namedtuple ( "Edge", "start, end, cost") class Graph (): def __init __ (self, edges): self .edges \u003d edges2 \u003d self.vertices \u003d set (sum ((for e in edges2),)) def dijkstra (self, source, dest): assert source in self.vertices dist \u003d (vertex: inf for vertex in self.vertices ) previous \u003d (vertex: None for vertex in self.vertices) dist \u003d 0 q \u003d self.vertices.copy () neighbours \u003d (vertex: set () for vertex in self.vertices) for start, end, cost in self. edges: neighbours.add ((end, cost)) #pp (neighbours) while q: u \u003d min (q, key \u003d lambda vertex: dist) q.remove (u) if dist [u] \u003d\u003d inf or u \u003d \u003d dest: break for v, cost in neighbours [u]: alt \u003d dist [u] + cost if alt< dist[v]: # Relax (u,v,a) dist[v] = alt previous[v] = u #pp(previous) s, u = deque(), dest while previous[u]: s.pushleft(u) u = previous[u] s.pushleft(u) return s graph = Graph([("a", "b", 7), ("a", "c", 9), ("a", "f", 14), ("b", "c", 10), ("b", "d", 15), ("c", "d", 11), ("c", "f", 2), ("d", "e", 6), ("e", "f", 9)]) pp(graph.dijkstra("a", "e")) Output: ["a", "c", "d", "e"]

    Шлях по пунктирною лінії на зображенні коротше, ніж по суцільній. А тепер трохи трохи докладніше на прикладі морських маршрутів:

    Якщо здійснювати плавання постійним курсом, то траєкторія руху судна по земної поверхні буде являти собою криву, яка називається в математиці логарифмічноюспіраллю.

    В навігації ця складна двоякою кривизни лінія називається локсодромії, що в перекладі з грецької мови означає «косою біг».

    Однак найкоротша відстань між двома точками на земній кулі вимірюється по дузі великого кола.

    Дуга великого кола виходить як слід від перетину земної поверхні з площиною, що проходить через центр Землі, прийнятої за кулю.

    В навігації дуга великого кола отримала назву ортодромія, що в перекладі означає «прямий біг». Другою особливістю ортодромії є те, що вона перетинає меридіани під різними кутами (рис. 29).

    Різниця відстаней між двома точками на земній поверхні по локсодромії і ортодромії має практичне значення тільки при великих океанських переходах.

    У звичайних же умовах цієї різницею нехтують і плавання здійснюють на постійному курсі, тобто по локсодромії.

    Для виведення рівняння візьмемо на локсодромії (рис. 30, а) дві точки Аі В,відстань між якими елементарно мало. Провівши через них меридіани і паралель, отримаємо елементарний прямокутний сферичний трикутник ABC.У цьому трикутнику кут, утворений перетином меридіана і паралелі, прямий, а кут, P nABдорівнює курсу судна К. Катет АСпредставляє відрізок дуги меридіана і його можна виразити

    де R - радіус Землі, прийнятої за кулю;

    Δφ - елементарне прирощення широти (різниця широт).

    катет СВпредставляє відрізок дуги паралелі

    де r - радіус паралелі;

    Δλ - елементарна різниця довгот.

    З треуголніка OO 1 C можна знайти, що

    Тоді в остаточному вигляді катет СВможна висловити так:

    Беручи елементарний сферичний трикутник ABCза плоский, напишемо

    після скорочення R і заміни елементарно малих збільшень координат нескінченно малими матимемо

    Проинтегрируем отриманий вираз в межах від φ 1, λ 1 до φ 2, λ 2 вважаючи значення tgK величиною постійною:

    У правій частині маємо табличний інтеграл. Після підстановки його значення отримаємо рівняння локсодромії на кулі

    Аналіз цього рівняння дозволяє зробити наступні висновки:

    При курсах 0 і 180 ° локсодроми перетворюється в дугу великого кола - меридіан;

    При курсах 90 і 270 ° локсодроми збігається з паралеллю;

    Локсодромія перетинає кожну паралель тільки один раз, а кожен меридіан - незліченну кількість разів. тобто спиралеобразно наближаючись до полюса вона його не досягає.

    Плавання постійним курсом, т. Е. По локсодромії, хоча вона і не є найкоротшим відстанню між двома точками на Землі, представляє для судноводія значні зручності.

    Вимоги, що пред'являються до морської навігаційній карті, можна сформулювати, грунтуючись на перевазі плавання по локсодромії і результатах аналізу її рівняння наступним чином.

    1. Локсодромія, перетинаючи меридіани під постійним кутом, повинна зображуватися прямою лінією.

    2. Картографічна проекція, яка використовується для побудови карт, повинна бути рівнокутної, щоб курси, пеленги і кути на ній відповідали своїм значенням на місцевості.

    3. Меридіани і паралелі, як лінії курсів 0, 90, 180 ° і 270 °, повинні бути взаємно перпендикулярними прямими лініями.

    Найкоротшим відстанню між двома даними точками на поверхні Землі, прийнятої за кулю, є менша з дуг великого кола, що проходить через ці точки. Крім випадку проходження судна по меридіану або екватору, ортодромія перетинає меридіани під різними кутами. Тому судно, наступне по такій кривій, повинне весь час змінювати свій курс. Практично зручніше слідувати по курсу, що становить постійний кут з меридіанами і зображуваного на карті в проекції Меркатора прямою лінією - локсодромії. Однак на великих відстанях відмінність в довжині ортодромії і локсодромії досягає значної величини. Тому в таких випадках розраховують ортодромії і намічають на ній проміжні точки, між якими здійснюють плавання по локсодромії.

    Картографічна проекція, яка задовольнить переліченим вимогам, була запропонована голландським картографом Герардом Крамером (Меркатором) в 1569 р честь її творця проекція отримала назву меркаторской.

    А хто хоче почерпнути ще більше цікавої інформації дізнайтеся більше Оригінал статті знаходиться на сайті ІнфоГлаз.рф Посилання на статтю, з якої зроблена ця копія -