• 2点間の最短距離。 なぜそれが弧よりも直線にあるのか知っていますか? 2本の交差する線の間の距離を決定する

    01.02.2022

    黒板にチョークで2つのポイントの輪郭を描いた後、教師は若い生徒にタスクを提供します。それは、両方のポイント間の最短経路を描くことです。

    生徒は考えた後、彼らの間に曲がりくねった線を熱心に描きます。

    -それが最短の方法です! 先生は驚いています。 -誰が教えてくれましたか?

    - 私の父。 彼はタクシーの運転手です。

    もちろん、素朴な男子生徒の絵は逸話的ですが、図の点線の弧を言われたら、あなたは笑わないでしょう。 1は、喜望峰からオーストラリアの南端までの最短の道です。

    さらに印象的なのは、次のステートメントです。 日本からパナマ運河への往復2回は、同じ地図上でそれらの間に引かれた直線よりも短いです!

    米。 1.海図では、喜望峰からオーストラリアの南端までの最短ルートは、直線(「等角航路」)ではなく、曲線(「等角航路」)で示されます。


    これはすべて冗談のように見えますが、その間、あなたが議論の余地のない真実になる前に、カートグラファーによく知られています。




    米。 2.海図上の横浜とパナマ運河を結ぶ曲線が、同じ地点を結ぶ直線よりも短いのは信じられないほどです。


    この問題を明確にするために、海図全般、特に海図についていくつかの言葉を述べる必要があります。 地球は球体であるため、地球の表面の一部を紙に描くことは、原則として簡単な作業ではありません。また、球形の表面のどの部分も、折り目や破損なしに平面に配置することはできないことが知られています。 思わず、地図上の避けられない歪みに我慢しなければなりません。 マップを描画する多くの方法が発明されましたが、すべてのマップに欠点がないわけではありません。ある種類の歪みがあるものと、別の種類の歪みがあるものがありますが、歪みのないマップはありません。

    船乗りは、16世紀の古いオランダの地図製作者および数学者の方法に従って描かれた地図を使用します。 メルカトル。 この方法はメルカトル図法と呼ばれます。 海図は長方形のグリッドで簡単に識別できます。子午線は一連の平行な直線として表示されます。 緯線-最初の緯線に垂直な直線でもあります(図5を参照)。

    ここで、同じ平行線上にある1つの海港から別の海港への最短経路を見つけたいと想像してみてください。 海上では、すべてのパスが利用可能であり、それがどのようにあるかを知っていれば、最短パスに沿ってそこを移動することが常に可能です。 私たちの場合、最短経路は両方のポートが存在する平行線に沿っていると考えるのが自然です。結局のところ、地図上では直線であり、直線経路よりも短くなる可能性があります。 しかし、私たちは間違っています。平行線に沿ったパスは、最短ではありません。

    実際、球の表面では、2点間の最短距離は、それらを結ぶ大円の弧です。 しかし、平行の円 小さな 円。 大きな円の弧は、同じ2点を通る小さな円の弧よりも曲率が小さくなります。半径が大きいほど、曲率は小さくなります。 地球上の糸を2点の間で引っ張ります(図3を参照)。 あなたはそれが平行に全く沿っていないことを確認するでしょう。 引き伸ばされた糸は最短経路の明白な指標であり、それが地球上の平行線と一致しない場合、海図では最短経路は直線で示されません:平行線の円がそのようなものに描かれていることを忘れないでください直線による地図、直線と一致しない線、 曲線 .



    米。 3. 2点間の本当に最短経路を見つける簡単な方法:これらの点の間で地球上の糸を引く必要があります


    言われたことの後で、海図の最短経路が直線ではなく曲線として描かれている理由が明らかになります。

    彼らは、ニコラエフ(現在のオクチャブルスカヤ)鉄道の方向を選択するとき、それをどのように敷設するかについて無限の論争があったと言います。 論争は、問題を文字通り「簡単に」解決した皇帝ニコライ1世の介入によって終結しました。彼は、サンクトペテルブルクとモスクワを線に沿って接続しました。 もしこれがメルカトル図法で行われていたら、それは恥ずかしい驚きだったでしょう。直線ではなく、道路はカーブであることが判明したでしょう。

    計算を避けない人は、簡単な計算で、地図上で曲がっているように見えるパスが、まっすぐに考える準備ができているパスよりも実際には短いと確信できます。 2つの港が60度線上にあり、60°の距離で隔てられているとします。 (もちろん、そのような2つの港が実際に存在するかどうかは、計算には重要ではありません。)



    米。 4.平行の弧と大円の弧に沿ったボール上の点AとBの間の距離の計算に


    イチジクに 4点 O-地球の中心、 AB-港が横たわる緯線の弧 AとB; の彼女の60°。 緯線の中心はある点にあります から中心から想像してみてください O地球儀は同じ港を通り抜けて描かれています大円の弧:その半径 OB = OA = R;描かれた弧の近くを通過します AB、しかし、それは一致しません。

    各円弧の長さを計算してみましょう。 ポイント以来 しかし緯度60°にあり、半径 OAOVで補う OS(地球の軸)30°の角度。 直角三角形で そうAC(= r)、 30°の角度の反対側にあることは斜辺の半分に等しい JSC;

    意味、 r = R / 2弧長 ABは緯度の円の6分の1の長さであり、この円は大きな円の半分の長さ(半径の半分に相当)であるため、小さな円の弧の長さです。



    同じ点の間に描かれた大円の弧の長さ(つまり、それらの間の最短経路)を決定するには、角度の大きさを知る必要があります AOW。コード なので、円弧を60°(小さな円)に引くと、同じ小さな円に内接する正六角形の辺になります。 それが理由です AB \ u003d r \ u003d R / 2

    直線を描く od、コネクティングセンター O真ん中の地球 D和音 AB、直角三角形を取得します ODA、角度はどこですか D-真っ直ぐ:

    DA =1/2ABおよびOA=R。

    sinAOD = AD:AO = R / 4:R = 0.25

    ここから(表によると)次のことがわかります。

    =14°28"、5

    それゆえ

    =28°57"。

    今では、最短経路の希望の長さをキロメートルで見つけることは難しくありません。 地球の大円の1分間の長さが次のようになっていることを思い出せば、計算を簡略化できます。

    海図に直線で示されている緯線に沿った経路は3333kmであり、大きな円に沿った経路(地図上の曲線に沿った経路)は3213 km、つまり120km短いことがわかります。

    糸で武装し、地球儀を手元に置いておくと、図面の正確さを簡単に確認でき、図面に示されているように大円の弧が実際にあることを確認できます。 図に示されています。 1アフリカからオーストラリアへの「まっすぐな」航路は、6020マイルであり、「曲線」は5450マイル、つまり570マイル(1050 km)短いかのようです。 ロンドンから上海への海図上の「直接」航空路はカスピ海を通りますが、実際に最短のルートはサンクトペテルブルクの北にあります。 これらの問題が時間と燃料の節約にどのような役割を果たしているかは明らかです。

    航海の時代に輸送時間が常に評価されていなかった場合、「時間」はまだ「お金」とは見なされていませんでした。蒸気船の出現により、消費された石炭1トンごとに支払う必要があります。 そのため、私たちの時代には、船は本当に最短経路に沿って航行しており、多くの場合、メルカトル図法ではなく、いわゆる「中心」投影法で作成された地図を使用しています。これらの地図では、大円の弧が直線として描かれています。

    では、なぜ以前のナビゲーターはそのような欺瞞的な地図を使用し、好ましくない道を選んだのでしょうか? 昔、彼らが海図の現在示されている特徴について知らなかったと考えるのは間違いです。 もちろん、この問題はこれではなく、メルカトル図法に従って作成された海図が不便さとともに、船員にとって非常に貴重な利益をもたらすという事実によって説明されます。 このような地図は、最初に、等高線の角を維持しながら、歪みのない地球の表面の別々の小さな部分を示しています。 これは、赤道からの距離に応じて、すべての輪郭が著しく引き伸ばされるという事実と矛盾しません。 高緯度では、海図がその特徴に不慣れな人に大陸の本当のサイズの完全に誤った考えを刺激するほどストレッチが重要です:グリーンランドはアフリカ、アラスカと同じサイズのようですグリーンランドはアフリカの15分の1であり、アラスカとグリーンランドはオーストラリアの半分の大きさですが、オーストラリアよりも大きいです。 しかし、海図のこれらの機能に精通している船員は、それらに惑わされることはありません。 彼は彼らに我慢しました。特に、小さなエリアでは、海図が自然の正確な類似性を示しているからです(図5)。

    一方、海図は、航海練習のタスクの解決を大いに促進します。 これは、一定の進路をたどる船の進路が直線で描かれている唯一の種類の海図です。 「一定の進路」に従うということは、常に一方向、つまり明確な「等角航路」を維持すること、つまり、すべての子午線を同じ角度で横切るように進むことを意味します。 ただし、このパス(「等角航路」)は、すべての子午線が互いに平行な直線であるマップ上でのみ直線として描くことができます。 また、地球上では緯線が子午線と直角に交差しているため、このようなマップでは、緯線は子午線に垂直な直線である必要があります。 つまり、海図の特徴である座標グリッドに正確に到達します。




    米。 5.地球の航海またはメルカトル図法。 このようなマップでは、赤道から遠く離れた等高線の寸法が大幅に誇張されています。 たとえば、グリーンランドとオーストラリアのどちらが大きいですか? (テキストで答える)


    メルカトル図法に対する船員の好みが理解できるようになりました。 指定された港に行くときにたどるコースを決定したいので、ナビゲーターはパスの終点に定規を適用し、子午線との角度を測定します。 この方向に常に外洋を維持することで、ナビゲーターは船を正確に目標に到達させます。 「等角航路」は、最短でも経済的でもありませんが、ある意味で船員にとって非常に便利な方法であることがわかります。 たとえば、喜望峰からオーストラリアの南端まで到達するには(図1を参照)、常に同じコースS 87°、50 "を維持する必要があります。一方、船を同じ場所に運ぶには最短経路(「」に沿った)の最終点では、図からわかるように、船の進路を継続的に変更する必要があります。S42°、50 "のコースから開始し、Nのコースで終了します。 53°.50"(この場合、最短経路は実現可能ではありません。南極の氷壁にあります)。

    「等角航路」と「等角航路」に沿った両方の経路は、大円に沿った経路が海図に直線として描かれている場合、つまり赤道に沿って、または子午線に沿って移動する場合にのみ一致します。 他のすべての場合、これらのパスは異なります。

    (画法幾何学)
  • CD(CXDX、C2D2)ドットで表示 C5 = D5 A5B5等しい...
    (画法幾何学)
  • 2つの平行な平面間の距離の決定
    一般位置01での2つの平行な平面間の距離の決定| バツ同じ2つの平面間の距離を決定し、投影された平面の位置に変換するという問題に減らすと便利です。 この場合、平面間の距離は、線の間の垂線として定義されます...
    (画法幾何学)
  • 2本の交差する線の間の距離を決定する
    2つの交差する線の間の最短距離を決定する場合は、投影面のシステムを2回変更する必要があります。 この問題を解決するとき、直接 CD(CXDX、C2D2)ドットで表示 C5 = D5(図198)。 この点から投影までの距離 A5B5等しい...
    (画法幾何学)
  • 2つの交差する直線間の角度
    これは、データに平行な2本の交差する線の間の角度です。 したがって、このタスクは前のタスクと同様です。 これを解決するには、任意の点を取り、指定されたねじれの位置に平行に2本の線を引き、投影変換を使用して必要な角度を決定する必要があります。
    (画法幾何学の基礎。短いコースと問題のコレクション。)
  • 2つの平行線間の距離の決定
    この問題は、投影面を二重に置き換える方法によって解決されます。 最終段階では、投影面の1つが交差する線の1つに垂直である必要があります。 次に、それらの間の最短距離は、他のスキューラインに垂直なセグメントの値によって決定されます(図199)。
    (画法幾何学)
  • 写真の点線に沿ったパスは、実線に沿ったパスよりも短くなっています。 そして今、航路の例についてもう少し詳しく説明します。

    一定のコースで航海する場合、地表での船の軌道は数学で呼ばれる曲線になります 対数螺旋。

    ナビゲーションでは、この複雑な二重曲率線はと呼ばれます 等角航路, これはギリシャ語で「斜めの走り」を意味します。

    ただし、地球上の2点間の最短距離は、大円の弧に沿って測定されます。

    大円の弧は、地球の表面と地球の中心を通る平面との交点からのトレースとして取得され、ボールと見なされます。

    ナビゲーションでは、大圏弧は 大円, これは「直進」を意味します。 大円の2つ目の特徴は、子午線をさまざまな角度で横切ることです(図29)。

    等角航路と等角航路に沿った地表の2点間の距離の違いは、大圏を横断する場合にのみ実際に重要です。

    通常の状態では、この違いは無視され、ナビゲーションは一定のコースで実行されます。 loxodromeによる。

    方程式を導き出すために、等角航路を取ります(図30 a) 2つのドット しかしで、それらの間の距離は単純に小さいです。 子午線とそれらを通る平行線を描くと、基本的な直角三角形が得られます。 ABC。この三角形では、子午線と平行線の交点がなす角度が右で、角度が PnAB船のコースに等しいK.Katet 交流子午線弧セグメントを表し、表現できます

    どこ R -球体と見なされる地球の半径。

    Δφ-緯度の基本増分(緯度の差)。

    SW平行な円弧セグメントを表します

    ここでr -平行線の半径;

    Δλ -経度の基本的な違い。

    三角形からOO1C 見つけることができます

    その後、最終的な形で脚 SWこのように表現することができます:

    基本的な球面三角形を仮定します ABCフラットの場合は、

    削減後 R 座標の基本的な小さな増分を微小なものに置き換えると、次のようになります。

    結果の式をφ1、λ1からφ2の範囲で統合します。 λ 2 tgKの値を定数値と見なします。

    右側には表形式の積分があります。 その値を代入した後、ボールの等角航路方程式を取得します

    この方程式を分析すると、次の結論を導き出すことができます。

    0°と180°のコースでは、等角航路は大円の弧、つまり子午線に変わります。

    90°と270°のコースでは、等角航路は平行と一致します。

    等角航路は各平行線を1回だけ通過し、各子午線は数え切れないほどの回数交差します。 それらの。 らせん状にポールに近づいても、ポールには届きません。

    一定のコース、つまり等角航路に沿ったナビゲーションは、地球上の2点間の最短距離ではありませんが、ナビゲーターにとってかなりの便利さを表しています。

    航海図の要件は、等角航路に沿った航海の利点とその方程式の分析結果に基づいて次のように定式化できます。

    1.子午線を一定の角度で横切る等角航路は、直線として描く必要があります。

    2.地図の作成に使用される地図投影法は、その上のコース、方位、および角度が地上での値に対応するように、等角である必要があります。

    3.子午線と緯線は、コースライン0、90、180°、270°のように、相互に垂直な直線である必要があります。

    球体と見なされる、地球の表面上の2つの指定されたポイント間の最短距離は、これらのポイントを通過する大円の弧の小さい方です。 子午線または赤道をたどる船の場合を除いて、大円はさまざまな角度で子午線を横切ります。 したがって、このようなカーブをたどる船は、常に進路を変更する必要があります。 子午線と一定の角度をなし、メルカトル図法の地図上に直線(等角航路)で描かれているコースをたどる方が実際には便利です。 ただし、遠距離では、オルソドロームとロキソドロームの長さの差が大きな値に達します。 したがって、そのような場合、オルソドロームが計算され、その上に中間点がマークされ、その間でロクソドロームに沿って泳ぎます。

    上記の要件を満たす地図作成投影法は、1569年にオランダの地図製作者Gerard Cramer(Mercator)によって提案されました。その作成者に敬意を表して、投影法は名前が付けられました。 メルカトル。

    そして、もっと興味深い情報を学びたい人はもっと知りたい 元の記事はウェブサイトにあります InfoGlaz.rfこのコピーが作成された記事へのリンク-

    距離、距離、cf。 1. 2つのポイントを区切るスペース、何かの間のギャップ。 直線上の2点間の最短距離。 私たちから2キロの距離に住んでいます。 「司令官は彼らを最も近い距離に入れました... ウシャコフ一義辞典

    距離-名詞、s。、使用します。 しばしば形態学:(いいえ)何ですか? 何のための距離? 距離、(参照)何? 距離より? 距離、何? 距離について; pl。 何? 距離、(いいえ)何? 距離、なぜ? 距離、(参照)何? 距離より? 距離... Dmitrievの辞書

    距離- 私; cf. 2点、2点などを隔てる空間、lよりも誰かの間のギャップ。 最短の川 2点間。 R.家から学校へ。 近くの川に後退します。 メートルの距離で、腕を伸ばした。 何かを知って、何かを感じてください。 …… 百科事典の辞書

    距離- 私; cf. も参照してください 距離a)2点、2つの物体などを隔てる空間、lよりも誰かの間のギャップ。 2点間の最短距離。 家から学校までの距離。 近距離に後退/nie..。 多くの表現の辞書

    幾何学-さまざまな形状(点、線、角度、2次元および3次元のオブジェクト)のプロパティ、それらのサイズ、および相対位置を研究する数学の分野。 教育の便宜のために、幾何学は面積測定と立体幾何学に分けられます。 で… … コリアーズ百科事典

    ナビゲーション*

    ナビゲーション-航海部門(を参照)。コンパスと丸太を使用して、海上での船の位置を特定する方法のプレゼンテーションを締めくくります(を参照)。 海上での船の位置を決定することは、船が現在位置している地点を地図上に置くことを意味します。 百科事典の辞書F.A. ブロックハウスとI.A. エフロン

    コージェネ-(コーエン)ヘルマン(1842 1918)ドイツの哲学者、創設者、そして新カント派のマールブルグ派の最も著名な代表者。 主な作品:「カントの経験理論」(1885)、「カントの倫理の正当化」(1877)、「カントの美学の正当化」(1889)、「論理…..。

    カント・イマヌエル-カントの人生の道と著作イマヌエル・カントは、1724年に東プロイセンのコニグスベルク(現在のカリーニングラード)で生まれました。父親はサドラー、母親は主婦で、6人の子供は成人期まで生きていませんでした。 カントはいつも両親を覚えていました...... その起源から現在までの西洋哲学

    カントの批判的哲学:能力の教義-(La philosophie critique de Kant:Doctrines des facultes、1963)ドゥルーズ著。 序文で超越的な方法を説明し、ドゥルーズは、カントが哲学をすべての知識と本質的な目標との関係の科学として理解していると述べています... ... 哲学の歴史:百科事典

    農場の原則-幾何光学の基本原理(幾何光学を参照)。 F. p。の最も単純な形式は、光線が常に、その通過時間が...未満であるパスに沿った2点間の空間を伝播するというステートメントです。 ソビエト大百科事典

    ダイクストラのアルゴリズムは、1959年にオランダの科学者エドガーダイクストラによって発明されたグラフアルゴリズムです。 グラフの頂点の1つから他のすべての頂点への最短経路を検索します。 アルゴリズムは機能します 負の重みのエッジがないグラフの場合のみ。

    図に示すグラフの例でアルゴリズムを実行することを検討してください。

    最初の頂点から他のすべての頂点までの最短距離を見つける必要があるとします。

    円は頂点を示し、線は頂点間のパス(グラフのエッジ)を示します。 頂点の数は円で示され、それらの「価格」(パスの長さ)はエッジの上に示されます。 各頂点の横に、赤いラベルがマークされています。これは、頂点1からこの頂点までの最短経路の長さです。

    最初の一歩。 この例では、ダイクストラのアルゴリズムのステップを考えてみましょう。 頂点1には最小のラベルがあり、頂点2、3、および6が隣接しています。

    次に、頂点1の最​​初の隣接点は頂点2です。これは、頂点1へのパスの長さが最小であるためです。 頂点1を通るパスの長さは、頂点1のラベルの値と、1番目から2番目までのエッジの長さの合計に等しくなります。つまり、0 + 7=7です。頂点2の現在のラベルは無限大なので、2番目の頂点の新しいラベルは7です。

    1番目の頂点の他の2つの隣接点(3番目と6番目)で同様の操作を実行します。

    ノード1のすべてのネイバーがチェックされます。 ピーク1までの現在の最小距離は最終的なものと見なされ、修正の対象にはなりません(これが実際に当てはまるという事実は、E。ダイクストラによって最初に証明されました)。 グラフからそれを消して、この頂点にアクセスしたことをマークします。

    第二段階。 アルゴリズムのステップが繰り返されます。 ここでも、未訪問の頂点の「最も近い」ものが見つかります。 これは、7というラベルの付いた頂点2です。

    ここでも、選択した頂点の隣接する頂点のラベルを減らして、2番目の頂点を通過させようとします。 頂点2の隣接は、頂点1、3、および4です。

    頂点2の最初の(順番に)隣接する頂点は頂点1ですが、すでにアクセスされているため、最初の頂点には何もしません。

    頂点2の次の隣接点は頂点3です。これは、未訪問としてマークされた頂点の最小ラベルがあるためです。 2を通過すると、そのようなパスの長さは17(7 + 10 = 17)になります。 ただし、3番目の頂点の現在のラベルは9であり、17未満であるため、ラベルは変更されません。

    頂点2のもう1つの隣接点は、頂点4です。2番目を通過すると、そのようなパスの長さは、2番目の頂点までの最短距離と頂点2と4の間の距離の合計に等しくなります。 、22(7 + 15 = 22)。 22年以降<, устанавливаем метку вершины 4 равной 22.

    頂点2のすべての隣接が表示されました。頂点までの距離を固定し、訪問済みとしてマークします。

    3番目のステップ。 頂点3を選択して、アルゴリズムのステップを繰り返します。その「処理」の後、次の結果が得られます。

    次のステップ。 残りの頂点に対してアルゴリズムのステップを繰り返します。 これらはそれぞれ頂点6、4、5になります。

    アルゴリズム実行の完了。 頂点を処理できなくなると、アルゴリズムは終了します。 この例では、すべての頂点が取り消し線で囲まれていますが、どの例でもこれが当てはまると想定するのは誤りです。一部の頂点は、到達できない場合、つまりグラフが切断されている場合、取り消し線が引かれないままになる可能性があります。 アルゴリズムの結果は、最後の図に示されています。頂点1から2への最短経路は7、3は9、4は20、5は20、6は11です。

    さまざまなプログラミング言語でのアルゴリズムの実装:

    C ++

    #include "stdafx.h" #include 名前空間stdを使用します。 const int V = 6; //ダイクストラのアルゴリズムvoidDijkstra(int GR [V] [V]、int st)(int distance [V]、count、index、i、u、m = st + 1; bool visited [V]; for(i = 0 i "< "<> "; cin >> start; Dijkstra(GR、start-1); system(" pause >> void ");)

    パスカル

    プログラムDijkstraAlgorithm; usecrt; constV = 6; inf = 100000; タイプvector=整数の配列; var start:整数; const GR:整数の配列=((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)); (ダイクストラのアルゴリズム)プロシージャダイクストラ(GR:整数の配列; st:整数); var count、index、i、u、m、min:整数; 距離:ベクトル; 訪問:ブール値の配列。 beginm:= st; for i:= 1 to V do begin distance [i]:= inf; 訪問した[i]:= false; 終わり; 距離:= 0; count:= 1からV-1の場合、min:=infを開始します。 for i:= 1 to V do if(notvisited [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)および(distance [u]<>inf)および(distance [u] + GR inf then writeln(m、 ">"、i、 "="、distance [i])else writeln(m、 ">"、i、 "="、 "ルートが利用できません"); 終わり; (メインプログラムブロック)clrscrを開始します。 write( "開始ノード>>"); read(開始); ダイクストラ(GR、開始); 終わり。

    Java

    import java.io.BufferedReader; import java.io.IOException; インポートjava.io.InputStreamReader; import java.io.PrintWriter; import java.util.ArrayList; java.util.Arraysをインポートします。 インポートjava.util.StringTokenizer; public class Solution(private static int INF = Integer.MAX_VALUE / 2; private int n;//digraphの頂点の数privateintm;//digraphのアークの数privateArrayList adj; //隣接リストprivateArrayList 重さ; //使用される有向グラフのプライベートブール値のエッジの重み; //渡されたピークと渡されなかったピークに関する情報を格納するための配列privateintdist; //開始頂点からの距離を格納する配列//開始頂点から最短パスを復元するために必要な祖先の配列privateintpred; int start; //開始頂点。​​そこから他のすべての距離が検索されますprivateBufferedReadercin; プライベートPrintWritercout; プライベートStringTokenizerトークナイザー; //開始頂点からダイクストラのアルゴリズムを開始する手順privatevoiddejkstra(int s)(dist [s] = 0; //開始頂点までの最短距離は0です(int iter = 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 = new ArrayList [n]; for(int i = 0; i< n; ++i) { weight[i] = new ArrayList(); )//(int i =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(); } }

    別のオプション:

    java.io.*をインポートします。 importjava.util。*; public class Dijkstra(private static final Graph.Edge GRAPH =(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 = "a"; private static final String END = "e"; public static void main(String args)(Graph g = new Graph(GRAPH); g.dijkstra (START); g.printPath(END); //g.printAllPaths();))class Graph(private final Map グラフ; //エッジのセットから構築された頂点名の頂点オブジェクトへのマッピング/**グラフの1つのエッジ(グラフコンストラクターでのみ使用)* / public static class Edge(public final String v1、v2; public final int dist; public Edge(String v1、String v2、int dist)(this.v1 = v1; this.v2 = v2; this.dist = dist;))/ **グラフの1つの頂点、隣接する頂点へのマッピングを完了* / public staticclassVertexはComparableを実装します (public final String name; public int dist = Integer.MAX_VALUE;//MAX_VALUEは無限大と見なされますpublicVertexprevious = null; public final Map 隣人=新しいHashMap<>(); public Vertex(String name)(this.name = name;)private void printPath()(if(this == this.previous)(System.out.printf( "%s"、this.name);)else if( this.previous == null)(System.out.printf( "%s(unreached)"、this.name);)else(this.previous.printPath(); System.out.printf( "->%s( %d) "、this.name、this.dist);))public int compareTo(Vertex other)(return Integer.compare(dist、other.dist);))/**エッジのセットからグラフを作成します* / public Graph(Edge edge)(graph = new HashMap<>(edges.length); //(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));)//(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);//また無向グラフに対してこれを実行します))/**指定されたソース頂点を使用してdijkstraを実行します*/ public void dijkstra(String startName)(if(!graph.containsKey(startName))(System.err.printf("グラフはしません開始頂点を含む\"%s \" \ n "、startName); return;)final Vertex source =graph.get(startName); NavigableSet q=新しいTreeSet<>(); //(Vertex v:graph.values())(v.previous = v == source?source:null; v.dist = v == source?0:Integer.MAX_VALUE; q.add( v);)dijkstra(q); )/**バイナリヒープを使用したダイクストラのアルゴリズムの実装*/ private void dijkstra(final NavigableSet q)(Vertex u、v; while(!q.isEmpty())(u = q.pollFirst(); //最短距離の頂点(最初の反復はソースを返します)if(u.dist == Integer.MAX_VALUE) break; // u(およびその他の残りの頂点)は到達できないため、無視できます//各ネイバーまでの距離を調べて(Map.Entry a:u.neighbours.entrySet())(v = a.getKey();//この反復のネイバーfinalint AlternativeDist = 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

    #含む #含む #含む // #define BIG_EXAMPLE typedef struct node_t node_t、* heap_t; typedef struct edge_t edge_t; struct edge_t(node_t * nd;/*このエッジのターゲット*/edge_t * sibling;/*単一リンクリストの場合*/int len; /*エッジコスト*/); struct node_t(edge_t * edge;/*単一リンクされたエッジのリスト*/node_t * via;/*前のノードが最短経路にある場合*/double dist;/*元のノードからの距離*/char name; / * the、er 、name * / int heap_idx; /*距離を更新するためのヒープ位置へのリンク*/); /*---エッジ管理---*/ #ifdef BIG_EXAMPLE#define BLOCK_SIZE(1024 * 32-1)#else#define BLOCK_SIZE 15 #endif edge_t * edge_root = 0、* e_next = 0; / *メモリ管理のことは気にしないでください、それらは要点を超えています。ふりe_next = malloc(sizeof(edge_t))* / void add_edge(node_t * a、node_t * b、double d)(if(e_next == edge_root )(edge_root = malloc(sizeof(edge_t)*(BLOCK_SIZE + 1)); edge_root.sibling = e_next; e_next = edge_root + BLOCK_SIZE;)--e_next; e_next-> nd = b; e_next-> len = d; e_next -> sibling = a-> edge; a-> edge = e_next;)void free_edges()(for(; edge_root; edge_root = e_next)(e_next = edge_root.sibling; free(edge_root);))/ * ---優先キューのもの---*/ heap_t * heap; int heap_len; void set_dist(node_t * nd、node_t * via、double d)(int i、j;/*すでにより良いパスを知っていた*/if(nd-> via && d> = nd-> dist)return; / *既存のヒープエントリを検索するか、新しいヒープエントリを作成します* / nd-> dist = d; nd-> via = via; i = nd-> heap_idx; if(!i) i = ++ heap_len;/*アップヒープ*/for(; i> 1 && nd-> dist< heap->dist; i = j)(heap [i] = heap [j])-> heap_idx = i; heap [i] = nd; nd-> heap_idx = i; )node_t * pop_queue()(node_t * nd、* tmp; int i、j; if(!heap_len)return 0; / *先頭の要素を削除し、そこにテール要素をプルしてダウンヒープ* / nd = heap; tmp = heap; for (i = 1; i< heap_len && (j = i * 2) <= heap_len; i = j) { if (j < heap_len && heap[j]->dist> heap-> dist)j ++; if(heap [j]-> dist> = tmp-> dist)break; (heap [i] = heap [j])-> heap_idx = i; )heap [i] = tmp; tmp-> heap_idx = i; ndを返す; )/ *---Dijkstraのもの; 到達不能なノードがキューに入ることがない---*/ void calc_all(node_t * start)(node_t * Lead; edge_t * e; set_dist(start、start、0); while((lead = pop_queue()))for( e = Lead-> edge; e; e = e-> sibling)set_dist(e-> nd、lead、lead-> dist + e-> len);)void show_path(node_t * nd)(if(nd-> via == nd)printf( "%s"、nd-> name); else if(!nd-> via)printf( "%s(unreached)"、nd-> name); else(show_path(nd-> via); printf( "->%s(%g)"、nd-> name、nd-> dist);))int main(void)(#ifndef BIG_EXAMPLE int i;#define N_NODES( "f"-" a "+ 1)node_t * nodes = calloc(sizeof(node_t)、N_NODES); for(i = 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、"コスト"=> $ edge); $ neighbors [$ edge] = array( "end" => $ edge、 "cost" => $ edge); )$ vertices = array_unique($ verticals); foreach($ vertices as $ verbex)($ dist [$ verbex] = INF; $ previous [$ verbex] = NULL;)$ dist [$ source] = 0; $ Q = $ vertices; while(count($ Q)> 0)(//TODO-最小値を取得するためのより高速な方法を見つける$min = INF; foreach($ Q as $ verbex)(if($ dist [$ verbex]< $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

    コレクションからimportnamedtuple、queue from pprint import pprint as pp inf = float( "inf")Edge = namedtuple( "Edge"、 "start、end、cost")class Graph():def __init __(self、edges):self .edges = edge2 = self.vertices = set(sum((for e in edge2)、))def dijkstra(self、source、dest):self.verticesのソースをアサートdist =(vertex:self.verticesの頂点のinf )previous =(vertex:self.verticesの頂点の場合はなし)dist = 0 q = self.vertices.copy()neighbors =(vertex:self.verticesの頂点の場合はset())開始、終了、自己のコスト。エッジ:neighbors.add((end、cost))#pp(neighbours)while q:u = min(q、key = lambda Vertex:dist)q.remove(u)if dist [u]==infまたはu= = dest:vのブレーク、neighbors [u]のコスト:alt = dist [u]+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"]

    同様の記事