ระยะทางที่สั้นที่สุดระหว่างจุดสองจุด คุณรู้ไหมว่าทำไมมันจึงเป็นเส้นตรงมากกว่าส่วนโค้ง? การกำหนดระยะห่างระหว่างสองเส้นตัดกัน

01.02.2022

เมื่อร่างโครงร่างสองจุดบนกระดานดำด้วยชอล์ค ครูเสนองานให้นักเรียนรุ่นเยาว์: วาดเส้นทางที่สั้นที่สุดระหว่างจุดทั้งสอง

หลังจากคิด นักเรียนก็ลากเส้นคดเคี้ยวไปมาระหว่างพวกเขาอย่างขยันขันแข็ง

- นั่นเป็นวิธีที่สั้นที่สุด! ครูรู้สึกประหลาดใจ - ใครสอนคุณว่า?

- พ่อของฉัน. เขาเป็นคนขับแท็กซี่

แน่นอนว่าภาพวาดของเด็กนักเรียนไร้เดียงสานั้นเป็นเรื่องเล็ก ๆ น้อย ๆ แต่คุณจะไม่ยิ้มถ้าคุณบอกว่าส่วนโค้งในรูป 1 คือทางที่สั้นที่สุดจากแหลมกู๊ดโฮปไปจนถึงปลายด้านใต้ของออสเตรเลีย!

ที่โดดเด่นยิ่งกว่าคือข้อความต่อไปนี้: ปรากฎในรูปที่. การเดินทางไปกลับ 2 รอบจากญี่ปุ่นไปยังคลองปานามานั้นสั้นกว่าเส้นตรงที่ลากระหว่างพวกเขาในแผนที่เดียวกัน!

ข้าว. 1. บนแผนภูมิทะเล เส้นทางที่สั้นที่สุดจากแหลมกู๊ดโฮปไปจนถึงปลายด้านใต้ของออสเตรเลียไม่ได้ระบุด้วยเส้นตรง ("loxodrome") แต่เป็นเส้นโค้ง ("orthodromy")


ทั้งหมดนี้ดูเหมือนเป็นเรื่องตลก แต่ในขณะเดียวกัน ก่อนที่คุณจะเป็นความจริงที่เถียงไม่ได้ ซึ่งเป็นที่รู้จักกันดีในหมู่นักทำแผนที่




ข้าว. 2. ดูเหมือนไม่น่าเชื่อว่าเส้นทางโค้งที่เชื่อมโยโกฮาม่าบนแผนภูมิทะเลกับคลองปานามานั้นสั้นกว่าเส้นตรงที่ลากระหว่างจุดเดียวกัน


เพื่อชี้แจงปัญหา จะต้องพูดสองสามคำเกี่ยวกับแผนภูมิโดยทั่วไปและเกี่ยวกับแผนภูมิทางทะเลโดยเฉพาะ การแสดงภาพส่วนต่างๆ ของพื้นผิวโลกบนกระดาษไม่ใช่เรื่องง่าย แม้โดยหลักการแล้ว เนื่องจากโลกเป็นทรงกลม และเป็นที่ทราบกันดีอยู่แล้วว่าไม่มีส่วนใดของพื้นผิวทรงกลมที่สามารถนำมาใช้บนระนาบได้โดยไม่พับและหัก โดยไม่ได้ตั้งใจ เราต้องทนกับการบิดเบือนที่หลีกเลี่ยงไม่ได้บนแผนที่ มีการคิดค้นวิธีการวาดแผนที่หลายวิธี แต่แผนที่ทั้งหมดไม่ได้ปราศจากข้อบกพร่อง: บางแผนที่มีการบิดเบือนในลักษณะเดียว บางประเภทแตกต่างกัน แต่ไม่มีแผนที่ที่ไม่มีการบิดเบือนเลย

กะลาสีเรือใช้แผนที่ที่วาดตามวิธีการของนักทำแผนที่และนักคณิตศาสตร์ชาวดัตช์สมัยศตวรรษที่ 16 เมอร์เคเตอร์ วิธีนี้เรียกว่าการฉายภาพ Mercator ง่ายต่อการจดจำแผนภูมิทะเลด้วยตารางสี่เหลี่ยม: เส้นเมอริเดียนจะแสดงเป็นชุดของเส้นตรงคู่ขนาน วงกลมละติจูด - เป็นเส้นตรงที่ตั้งฉากกับเส้นแรกด้วย (ดูรูปที่ 5)

ลองนึกภาพว่าตอนนี้คุณต้องการหาเส้นทางที่สั้นที่สุดจากท่าเรือมหาสมุทรหนึ่งไปยังอีกท่าเรือหนึ่งบนเส้นทางขนานเดียวกัน บนมหาสมุทร มีทุกเส้นทาง และสามารถเดินทางไปบนเส้นทางที่สั้นที่สุดได้เสมอหากคุณรู้ว่ามันอยู่อย่างไร ในกรณีของเรา เป็นเรื่องปกติที่จะคิดว่าเส้นทางที่สั้นที่สุดไปตามแนวขนานที่พอร์ตทั้งสองตั้งอยู่: ท้ายที่สุด บนแผนที่ มันคือเส้นตรง และสิ่งที่สั้นกว่าเส้นทางตรง! แต่เราคิดผิด เส้นทางขนานนั้นไม่สั้นที่สุดเลย

อันที่จริง: บนพื้นผิวของทรงกลม ระยะทางที่สั้นที่สุดระหว่างจุดสองจุดคือส่วนโค้งของวงกลมขนาดใหญ่ที่เชื่อมระหว่างจุดทั้งสอง แต่วงกลมคู่ขนาน เล็ก วงกลม. ส่วนโค้งของวงกลมขนาดใหญ่มีความโค้งน้อยกว่าส่วนโค้งของวงกลมเล็กๆ ใดๆ ที่ลากผ่านจุดสองจุดเดียวกัน: รัศมีที่ใหญ่กว่าจะสอดคล้องกับส่วนโค้งที่เล็กกว่า ดึงด้ายบนลูกโลกระหว่างจุดสองจุดของเรา (cf. รูปที่ 3); คุณจะแน่ใจว่ามันไม่ได้อยู่ตามแนวขนานเลย เส้นที่ยืดออกเป็นตัวบ่งชี้ที่เถียงไม่ได้ของเส้นทางที่สั้นที่สุด และหากเส้นนั้นไม่ตรงกับเส้นขนานในโลก แผนภูมิทะเล เส้นทางที่สั้นที่สุดจะไม่ถูกระบุด้วยเส้นตรง: โปรดจำไว้ว่าวงกลมของแนวขนานนั้นแสดงอยู่บนนั้น แผนที่โดยเส้นตรง เส้นใดที่ไม่ตรงกับเส้นตรง ก็มี เส้นโค้ง .



ข้าว. 3. วิธีง่ายๆ ในการค้นหาเส้นทางที่สั้นที่สุดระหว่างจุดสองจุด: คุณต้องดึงเธรดบนโลกระหว่างจุดเหล่านี้


หลังจากที่ได้พูดไปแล้ว เป็นที่ชัดเจนว่าเหตุใดเส้นทางที่สั้นที่สุดในแผนภูมิทะเลจึงไม่ปรากฏเป็นเส้นตรง แต่เป็นเส้นโค้ง

พวกเขาบอกว่าเมื่อเลือกทิศทางสำหรับเส้นทางรถไฟ Nikolaev (ปัจจุบันคือ Oktyabrskaya) มีข้อโต้แย้งไม่รู้จบเกี่ยวกับวิธีที่จะวางมัน ข้อพิพาทยุติลงโดยการแทรกแซงของซาร์นิโคลัสที่ 1 ซึ่งแก้ปัญหาได้ "ตรงไปตรงมา" อย่างแท้จริง: เขาเชื่อมโยงเซนต์ปีเตอร์สเบิร์กกับมอสโกตามสาย หากสิ่งนี้เกิดขึ้นบนแผนที่ Mercator มันคงเป็นเรื่องที่น่าอาย: แทนที่จะเป็นเส้นตรง ถนนจะกลายเป็นทางโค้ง

ผู้ที่ไม่หลีกเลี่ยงการคำนวณสามารถแน่ใจได้โดยการคำนวณง่ายๆ ว่าเส้นทางที่ดูคดเคี้ยวสำหรับเราบนแผนที่นั้นสั้นกว่าเส้นทางที่เราพร้อมพิจารณาโดยตรง ให้ท่าเรือทั้งสองของเราอยู่บนเส้นขนานที่ 60 และแยกจากกันเป็นระยะทาง 60° (แน่นอนว่าท่าเรือสองแห่งนั้นมีอยู่จริงหรือไม่นั้นไม่มีสาระสำคัญสำหรับการคำนวณ)



ข้าว. 4. การคำนวณระยะทางระหว่างจุด A และ B บนลูกบอลตามแนวโค้งของเส้นขนานและตามแนวโค้งของวงกลมใหญ่


ในรูป 4 คะแนน โอ -ศูนย์กลางของโลก, เอบี -ส่วนโค้งของวงกลมละติจูดที่ตั้งอยู่ A และ B; ใน 60° ของเธอ จุดศูนย์กลางของวงกลมละติจูดอยู่ที่จุดหนึ่ง จากลองนึกภาพว่าจากศูนย์ อู๋ของโลกถูกลากผ่านท่าเรือเดียวกันเป็นโค้งวงกลมใหญ่: รัศมีของมัน OB = OA = R;มันจะผ่านไปใกล้กับส่วนโค้งที่วาด เอบีแต่มันไม่ตรงกัน

มาคำนวณความยาวของส่วนโค้งแต่ละส่วนกัน ตั้งแต่จุด แต่และ ที่อยู่ที่ละติจูด 60° จากนั้นรัศมี OAและ OVแต่งหน้าด้วย OS(แกนโลก) ทำมุม 30° ในสามเหลี่ยมมุมฉาก ASOขา เอซี (=r),นอนอยู่ตรงข้ามมุม 30° เท่ากับครึ่งหนึ่งของด้านตรงข้ามมุมฉาก เจเอสซี;

วิธี, r=R/2ความยาวส่วนโค้ง ABคือความยาวหนึ่งในหกของวงกลมละติจูด และเนื่องจากวงกลมนี้มีความยาวครึ่งหนึ่งของวงกลมขนาดใหญ่ (เท่ากับครึ่งหนึ่งของรัศมี) เท่ากับความยาวของส่วนโค้งของวงกลมเล็ก



ในการกำหนดความยาวของส่วนโค้งของวงกลมใหญ่ที่ลากระหว่างจุดเดียวกัน (นั่นคือ เส้นทางที่สั้นที่สุดระหว่างจุดทั้งสอง) เราจำเป็นต้องทราบขนาดของมุม อ่าว.คอร์ด เช่นการลบส่วนโค้งเป็น 60 ° (วงกลมเล็ก) คือด้านของรูปหกเหลี่ยมปกติที่จารึกไว้ในวงกลมขนาดเล็กเดียวกัน นั่นเป็นเหตุผล AB \u003d r \u003d R / 2

วาดเส้นตรง อ้อศูนย์เชื่อมต่อ อู๋ลูกโลกตรงกลาง ดีคอร์ด เอบีได้สามเหลี่ยมมุมฉาก โอดีเอมุมไหน ด-ตรง:

DA= 1/2 AB และ OA=R

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

จากที่นี่เราพบ (ตามตาราง):

=14°28",5

และด้วยเหตุนี้

= 28°57"

ตอนนี้การหาความยาวที่ต้องการของเส้นทางที่สั้นที่สุดในหน่วยกิโลเมตรไม่ใช่เรื่องยาก การคำนวณสามารถทำให้ง่ายขึ้นได้หากเราจำได้ว่าความยาวหนึ่งนาทีของวงกลมใหญ่ของโลกคือ

เราเรียนรู้ว่าเส้นทางตามวงกลมละติจูดที่แสดงบนแผนภูมิทะเลเป็นเส้นตรงคือ 3333 กม. และเส้นทางตามวงกลมใหญ่ - ตามแนวโค้งบนแผนที่ - 3213 กม. หรือสั้นกว่า 120 กม.

ด้วยด้ายและลูกโลก คุณสามารถตรวจสอบความถูกต้องของภาพวาดของเราได้อย่างง่ายดาย และตรวจสอบให้แน่ใจว่าส่วนโค้งของวงกลมใหญ่นั้นอยู่จริงตามที่แสดงในภาพวาด แสดงในรูป 1 ราวกับว่าเส้นทางทะเล "ตรง" จากแอฟริกาไปยังออสเตรเลียคือ 6020 ไมล์ และ "โค้ง" - ​​5450 ไมล์ นั่นคือสั้นลง 570 ไมล์หรือ 1050 กม. เส้นทางบิน "ตรง" บนแผนภูมิทะเลจากลอนดอนไปยังเซี่ยงไฮ้ตัดผ่านทะเลแคสเปียน ในขณะที่เส้นทางที่สั้นที่สุดอยู่ทางเหนือของเซนต์ปีเตอร์สเบิร์ก ชัดเจนว่าปัญหาเหล่านี้มีบทบาทอย่างไรในการประหยัดเวลาและเชื้อเพลิง

หากในยุคของการเดินเรือเวลาการขนส่งไม่ได้มีค่าเสมอ - ดังนั้น "เวลา" ก็ยังไม่ถือว่าเป็น "เงิน" ดังนั้นด้วยการมาถึงของเรือไอน้ำ เราต้องจ่ายค่าถ่านหินส่วนเกินทุกตันที่บริโภค นั่นคือเหตุผลที่ในสมัยของเรา เรือแล่นไปตามเส้นทางที่สั้นที่สุด มักใช้แผนที่ที่ไม่ได้สร้างขึ้นใน Mercator แต่ในการฉายภาพที่เรียกว่า "ศูนย์กลาง": บนแผนที่เหล่านี้ ส่วนโค้งของวงกลมใหญ่จะแสดงเป็นเส้นตรง

แล้วทำไมอดีตนักเดินเรือจึงใช้แผนที่หลอกลวงและเลือกเส้นทางที่ไม่เอื้ออำนวย? เป็นความผิดพลาดที่จะคิดว่าในสมัยก่อนพวกเขาไม่รู้เกี่ยวกับคุณลักษณะที่ระบุไว้ในขณะนี้ของแผนภูมิทะเล แน่นอนว่าเรื่องนี้ไม่ได้อธิบายไว้ แต่ด้วยข้อเท็จจริงที่ว่าแผนภูมิที่วาดตามวิธีของ Mercator ร่วมกับความไม่สะดวก มีประโยชน์อันมีค่ามากสำหรับลูกเรือ ประการแรก แผนที่ดังกล่าวแสดงให้เห็นส่วนเล็กๆ ที่แยกจากกันของพื้นผิวโลกโดยไม่ผิดเพี้ยน โดยรักษามุมของรูปร่างไว้ สิ่งนี้ไม่ขัดแย้งกับความจริงที่ว่าด้วยระยะห่างจากเส้นศูนย์สูตร รูปทรงทั้งหมดจะยืดออกอย่างเห็นได้ชัด ที่ละติจูดสูง การยืดออกมีความสำคัญมากจนแผนภูมิทะเลเป็นแรงบันดาลใจให้บุคคลที่ไม่คุ้นเคยกับคุณสมบัติของมันด้วยความคิดที่ผิดๆ เกี่ยวกับขนาดที่แท้จริงของทวีป: กรีนแลนด์ดูเหมือนจะมีขนาดเท่ากับแอฟริกา อลาสก้า ใหญ่กว่าออสเตรเลีย แม้ว่ากรีนแลนด์จะเล็กกว่าแอฟริกาถึง 15 เท่า และอลาสก้าร่วมกับกรีนแลนด์ที่มีขนาดครึ่งหนึ่งของออสเตรเลีย แต่กะลาสีที่คุ้นเคยกับคุณลักษณะเหล่านี้ของแผนภูมิเป็นอย่างดีไม่สามารถหลอกพวกเขาได้ โดยเฉพาะอย่างยิ่งเมื่ออยู่ในพื้นที่เล็กๆ แผนผังทะเลให้ภาพเหมือนธรรมชาติ (รูปที่ 5)

ในทางกลับกัน แผนภูมิทะเลช่วยอำนวยความสะดวกในการแก้ปัญหาของการฝึกเดินเรืออย่างมาก นี่เป็นแผนภูมิประเภทเดียวที่แสดงเส้นทางของเรือในเส้นทางคงที่เป็นเส้นตรง การปฏิบัติตาม "หลักสูตรคงที่" หมายถึงการรักษาทิศทางเดียวอย่างสม่ำเสมอ "รูปสี่เหลี่ยมขนมเปียกปูน" กล่าวอีกนัยหนึ่งคือการข้ามเส้นเมอริเดียนทั้งหมดในมุมที่เท่ากัน แต่เส้นทางนี้ ("ล็อกโซโดรม") สามารถแสดงเป็นเส้นตรงได้เฉพาะในแผนที่ที่เส้นเมอริเดียนทั้งหมดเป็นเส้นตรงขนานกัน และเนื่องจากในโลกนี้ วงกลมของละติจูดตัดกับเส้นเมอริเดียนในมุมฉาก ดังนั้นในแผนที่ดังกล่าว วงกลมของละติจูดควรเป็นเส้นตรงตั้งฉากกับเส้นของเส้นเมอริเดียน กล่าวโดยสรุปคือ เรามาถึงเส้นตารางพิกัดอย่างแม่นยำซึ่งเป็นคุณลักษณะเฉพาะของแผนภูมิทะเล




ข้าว. 5. แผนที่ทะเลหรือ Mercator ของโลก ในแผนที่ดังกล่าว ขนาดของรูปทรงที่ห่างไกลจากเส้นศูนย์สูตรนั้นเกินจริงไปมาก ตัวอย่างใดที่ใหญ่กว่า: กรีนแลนด์หรือออสเตรเลีย (ตอบในข้อความ)


ความชอบของกะลาสีสำหรับแผนที่ Mercator เป็นที่เข้าใจได้แล้ว เมื่อต้องการกำหนดเส้นทางที่จะปฏิบัติตามเมื่อไปที่ท่าเรือที่กำหนด ผู้นำทางจะใช้ไม้บรรทัดกับจุดสิ้นสุดของเส้นทางและวัดมุมที่ทำกับเส้นเมอริเดียน โดยอยู่ในทะเลเปิดตลอดเวลาในทิศทางนี้ เนวิเกเตอร์จะนำเรือไปยังเป้าหมายอย่างแม่นยำ คุณเห็นว่า "loxodrome" แม้ว่าจะไม่ใช่ระยะสั้นและไม่ประหยัดที่สุด แต่ในบางแง่มุมเป็นวิธีที่สะดวกมากสำหรับกะลาสีเรือ เช่น จากแหลมกู๊ดโฮปไปจนถึงปลายด้านใต้ของออสเตรเลีย (ดูรูปที่ 1) จะต้องรักษาเส้นทางเดิม S 87 °, 50 "ไว้เสมอ ขณะเดียวกัน เพื่อที่จะนำเรือไปยังที่เดียวกัน จุดสุดท้ายในทางที่สั้นที่สุด (ตาม " ") จำเป็นต้องเปลี่ยนเส้นทางของเรืออย่างต่อเนื่องดังที่เห็นได้จากรูป: เริ่มจากหลักสูตร S 42 °, 50 "และสิ้นสุดด้วยหลักสูตร N 53 ° 50" (ในกรณีนี้ เส้นทางที่สั้นที่สุดไม่สามารถทำได้ด้วยซ้ำ - มันวางอยู่บนกำแพงน้ำแข็งของทวีปแอนตาร์กติกา )

ทั้งสองเส้นทาง - ตาม "ล็อกโซโดรม" และตาม "ออร์โธโดรม" - เกิดขึ้นพร้อมกันเฉพาะเมื่อเส้นทางตามวงกลมใหญ่ปรากฏบนแผนภูมิทะเลเป็นเส้นตรง: เมื่อเคลื่อนที่ไปตามเส้นศูนย์สูตรหรือตามเส้นเมอริเดียน ในกรณีอื่นๆ เส้นทางเหล่านี้ต่างกัน

(เรขาคณิตพรรณนา)
  • ซีดี (CXDX, C2D2)แสดงเป็น dot C5 = D5 A5B5เท่ากับ...
    (เรขาคณิตพรรณนา)
  • การกำหนดระยะห่างระหว่างระนาบคู่ขนานสองระนาบ
    การหาระยะห่างระหว่างระนาบขนานสองระนาบในตำแหน่งทั่วไป 01| Xสะดวกในการลดปัญหาในการกำหนดระยะห่างระหว่างระนาบสองลำเดียวกันซึ่งเปลี่ยนเป็นตำแหน่งของระนาบที่ยื่นออกมา ในกรณีนี้ ระยะห่างระหว่างระนาบถูกกำหนดให้เป็นแนวตั้งฉากระหว่างเส้น ...
    (เรขาคณิตพรรณนา)
  • การกำหนดระยะห่างระหว่างสองเส้นตัดกัน
    หากคุณต้องการกำหนดระยะทางที่สั้นที่สุดระหว่างเส้นตัดกันสองเส้น คุณต้องเปลี่ยนระบบของระนาบการฉายสองครั้ง เมื่อแก้ปัญหานี้โดยตรง ซีดี (CXDX, C2D2)แสดงเป็น dot C5 = D5(รูปที่ 198) ระยะทางจากจุดนี้ถึงประมาณการ A5B5เท่ากับ...
    (เรขาคณิตพรรณนา)
  • มุมระหว่างเส้นตรงสองเส้นตัดกัน
    นี่คือมุมระหว่างเส้นตัดสองเส้นที่ขนานกับข้อมูล ดังนั้นงานนี้จึงคล้ายกับงานก่อนหน้านี้ ในการแก้ปัญหานี้ คุณต้องใช้จุดใดก็ได้แล้วลากเส้นตรงสองเส้นผ่านจุดนั้น ขนานกับเส้นตรงเอียงที่ให้มา และใช้การแปลงการฉายภาพ กำหนดมุมที่ต้องการ....
    (พื้นฐานของเรขาคณิตพรรณนา หลักสูตรระยะสั้นและปัญหาต่างๆ)
  • การกำหนดระยะห่างระหว่างเส้นคู่ขนานสองเส้น
    ปัญหาได้รับการแก้ไขโดยวิธีการเปลี่ยนระนาบการฉายภาพสองเท่า ในขั้นตอนสุดท้าย ระนาบการฉายภาพต้องตั้งฉากกับเส้นตัดกันเส้นใดเส้นหนึ่ง จากนั้นระยะทางที่สั้นที่สุดระหว่างพวกเขาจะถูกกำหนดโดยค่าของส่วนของเส้นตั้งฉากกับเส้นเอียงอีกเส้นหนึ่ง (รูปที่ 199)....
    (เรขาคณิตพรรณนา)
  • เส้นทางตามเส้นประในภาพสั้นกว่าเส้นทางตามเส้นทึบ และตอนนี้มีรายละเอียดเพิ่มเติมเล็กน้อยเกี่ยวกับตัวอย่างเส้นทางเดินเรือ:

    หากคุณแล่นเรือในเส้นทางคงที่วิถีของเรือบนพื้นผิวโลกจะเป็นเส้นโค้งที่เรียกว่าคณิตศาสตร์ ลอการิทึมเกลียว.

    ในการนำทาง เส้นโค้งคู่ที่ซับซ้อนนี้เรียกว่า loxodromia, ซึ่งในภาษากรีกหมายถึง "การวิ่งเฉียง"

    อย่างไรก็ตาม ระยะทางที่สั้นที่สุดระหว่างจุดสองจุดบนโลกนั้นวัดตามส่วนโค้งของวงกลมใหญ่

    ส่วนโค้งของวงกลมใหญ่นั้นได้มาจากการลากเส้นจากจุดตัดของพื้นผิวโลกโดยมีระนาบผ่านศูนย์กลางของโลกซึ่งถ่ายเป็นลูกบอล

    ในการนำทาง วงเวียนใหญ่เรียกว่า วงกลมใหญ่, ซึ่งหมายถึง "วิ่งตรง" ลักษณะที่สองของวงกลมใหญ่คือมันตัดผ่านเส้นเมอริเดียนในมุมต่างๆ (รูปที่ 29)

    ความแตกต่างของระยะทางระหว่างจุดสองจุดบนพื้นผิวโลกตามแนวล็อกโซโดรมและออร์โธโดรมมีความสำคัญในทางปฏิบัติสำหรับการข้ามมหาสมุทรขนาดใหญ่เท่านั้น

    ภายใต้สภาวะปกติ ความแตกต่างนี้จะถูกละเลยและการนำทางเป็นเส้นทางคงที่ กล่าวคือ โดย ล็อกโซโดรม

    เพื่อให้ได้สมการ เราใช้ล็อกโซโดรมี (รูปที่ 30 เอ) สองจุด แต่และ ที่,ระยะห่างระหว่างพวกเขานั้นเล็กมาก การวาดเส้นเมอริเดียนและเส้นขนานผ่านเส้นทั้งสอง เราจะได้สามเหลี่ยมทรงกลมมุมฉากเบื้องต้น เอบีซีในรูปสามเหลี่ยมนี้ มุมที่เกิดจากจุดตัดของเส้นเมอริเดียนกับเส้นขนานเป็นมุมขวา และมุม พีABเท่ากับเส้นทางเดินเรือ ก.เกตุ ACแทนส่วนโค้งเมริเดียนและสามารถแสดงได้

    ที่ไหน R - รัศมีของโลกนำมาเป็นทรงกลม

    Δφ - การเพิ่มละติจูดเบื้องต้น (ความแตกต่างของละติจูด)

    ขา SWแทนส่วนโค้งขนานกัน

    ที่ไหน r - รัศมีของเส้นขนาน

    Δλ - ความแตกต่างเบื้องต้นของลองจิจูด

    จากสามเหลี่ยม OO 1 C จะพบว่า

    จากนั้นในรูปแบบสุดท้ายขา SWสามารถแสดงออกได้ดังนี้

    สมมติสามเหลี่ยมทรงกลมเบื้องต้น ABCสำหรับแบนเขียน

    หลังลด R และแทนที่การเพิ่มขึ้นเล็กน้อยของพิกัดเบื้องต้นด้วยพิกัดที่น้อยมากเรามี

    เรารวมนิพจน์ที่เป็นผลลัพธ์ไว้ในช่วงตั้งแต่ φ 1, λ 1 ถึง φ 2, λ 2 พิจารณาค่าของ tgK เป็นค่าคงที่:

    ทางด้านขวา เรามีอินทิกรัลแบบตาราง หลังจากแทนค่าแล้ว เราจะได้สมการล็อกโซโดรมบนลูกบอล

    การวิเคราะห์สมการนี้ทำให้เราสามารถสรุปได้ดังต่อไปนี้:

    ที่เส้นทาง 0 และ 180 ° ล็อกโซโดรมจะกลายเป็นส่วนโค้งของวงกลมใหญ่ - เส้นเมอริเดียน

    ที่สนาม 90 และ 270 ° loxodrome เกิดขึ้นพร้อมกับเส้นขนาน

    ล็อกโซโดรมตัดผ่านขนานกันเพียงครั้งเดียว และแต่ละเส้นเมอริเดียนมีจำนวนครั้งนับไม่ถ้วน เหล่านั้น. เกลียวเข้าหาเสาก็ไปไม่ถึง

    การนำทางในเส้นทางคงที่ กล่าวคือ ไปตามล็อกโซโดรม แม้ว่าจะไม่ใช่ระยะทางที่สั้นที่สุดระหว่างจุดสองจุดบนโลก แต่ก็แสดงถึงความสะดวกอย่างมากสำหรับผู้นำทาง

    ข้อกำหนดสำหรับแผนภูมิการนำทางทางทะเลสามารถกำหนดได้โดยอาศัยข้อดีของการนำทางไปตามล็อกโซโดรมและผลการวิเคราะห์สมการดังต่อไปนี้

    1. Loxodrome ที่ข้ามเส้นเมอริเดียนในมุมคงที่ควรแสดงเป็นเส้นตรง

    2. การฉายภาพแผนที่ที่ใช้ในการสร้างแผนที่ต้องสอดคล้องกัน เพื่อให้เส้นทาง แบริ่ง และมุมบนนั้นสอดคล้องกับค่าบนพื้น

    3. เส้นเมอริเดียนและเส้นขนาน เช่น เส้นสนาม 0, 90, 180° และ 270 ° ต้องเป็นเส้นตรงตั้งฉากซึ่งกันและกัน

    ระยะทางที่สั้นที่สุดระหว่างจุดสองจุดบนพื้นผิวโลกซึ่งถ่ายเป็นทรงกลมคือส่วนโค้งที่เล็กกว่าของวงกลมใหญ่ที่ผ่านจุดเหล่านี้ ยกเว้นในกรณีที่เรือเดินตามเส้นเมอริเดียนหรือเส้นศูนย์สูตร วงกลมใหญ่ตัดผ่านเส้นเมอริเดียนในมุมต่างๆ ดังนั้นเรือที่วิ่งตามโค้งดังกล่าวจะต้องเปลี่ยนเส้นทางตลอดเวลา ในทางปฏิบัติ จะสะดวกกว่าที่จะปฏิบัติตามเส้นทางที่สร้างมุมคงที่กับเส้นเมอริเดียน และแสดงไว้บนแผนที่ในการฉายภาพ Mercator ด้วยเส้นตรง - ล็อกโซโดรม อย่างไรก็ตาม ในระยะทางไกล ความแตกต่างในความยาวของออร์โธโดรมและล็อกโซโดรมถึงค่าที่มีนัยสำคัญ ดังนั้นในกรณีเช่นนี้ออร์โธโดรมคำนวณและทำเครื่องหมายจุดกึ่งกลางระหว่างที่ว่ายน้ำไปตามล็อกโซโดรม

    การฉายภาพแผนที่ที่ตรงตามข้อกำหนดข้างต้นได้รับการเสนอโดย Gerard Cramer นักเขียนแผนที่ชาวดัตช์ (Mercator) ในปี ค.ศ. 1569 เพื่อเป็นเกียรติแก่ผู้สร้าง การฉายภาพจึงถูกตั้งชื่อ เมอร์เคเตอร์

    และผู้ที่ต้องการเรียนรู้ข้อมูลที่น่าสนใจมากยิ่งขึ้น ค้นหาเพิ่มเติม บทความต้นฉบับอยู่ในเว็บไซต์ InfoGlaz.rfลิงก์ไปยังบทความที่ทำสำเนานี้ -

    DISTANCE ระยะทาง cf. 1. ช่องว่างคั่นสองจุด ช่องว่างระหว่างบางสิ่งบางอย่าง ระยะทางที่สั้นที่สุดระหว่างจุดสองจุดในแนวเส้นตรง อาศัยอยู่จากเราในระยะทางสองกิโลเมตร “ผู้บังคับบัญชาให้เข้าไปใกล้ที่สุด ... พจนานุกรมอธิบายของ Ushakov

    ระยะทาง- คำนาม s. ใช้ สัณฐานวิทยาบ่อยครั้ง: (ไม่) อะไรนะ? ห่างเพื่ออะไร? ระยะทาง (ดู) อะไร? ระยะทางกว่า? ระยะทาง อะไร? เกี่ยวกับระยะทาง พี อะไร? ระยะทาง (ไม่มี) อะไรนะ? ระยะทาง ทำไม? ระยะทาง (ดู) อะไร? ระยะทางกว่า? ระยะทาง... พจนานุกรมของ Dmitriev

    ระยะทาง- ฉัน; เปรียบเทียบ ช่องว่างที่คั่นสองจุด วัตถุสองชิ้น ฯลฯ ช่องว่างระหว่างบุคคล มากกว่า l แม่น้ำที่สั้นที่สุด ระหว่างสองจุด ร. จากบ้านไปโรงเรียน. ไปพักผ่อนที่แม่น้ำใกล้เคียง ในระยะหนึ่งเมตรกางแขนออก รู้อะไรบางอย่าง รู้สึกบางอย่าง บน… … พจนานุกรมสารานุกรม

    ระยะทาง- ฉัน; เปรียบเทียบ ดูสิ่งนี้ด้วย ระยะทาง ก) ช่องว่างที่แยกจุดสองจุด วัตถุสองชิ้น ฯลฯ ช่องว่างระหว่างบุคคล มากกว่า ล. ระยะทางที่สั้นที่สุดระหว่างจุดสองจุด ระยะทางจากบ้านไปโรงเรียน ถอยให้ห่างๆ / นี่ ... พจนานุกรมสำนวนมากมาย

    เรขาคณิต- สาขาวิชาคณิตศาสตร์ที่ศึกษาคุณสมบัติของรูปทรงต่างๆ (จุด เส้น มุม วัตถุสองมิติและสามมิติ) ขนาดและตำแหน่งสัมพัทธ์ เพื่อความสะดวกในการสอน เรขาคณิตแบ่งออกเป็นแบบแผนและเรขาคณิตแบบทึบ ที่… … สารานุกรมถ่านหิน

    การนำทาง*

    การนำทาง- กรมการเดินเรือ (ดู) สรุปการนำเสนอวิธีการกำหนดตำแหน่งของเรือในทะเลโดยใช้เข็มทิศและท่อนซุง (ดู) การกำหนดตำแหน่งของเรือในทะเลหมายถึงการวางตำแหน่งบนแผนที่ซึ่งปัจจุบันเรือตั้งอยู่ ... ... พจนานุกรมสารานุกรมเอฟเอ Brockhaus และ I.A. เอฟรอน

    COGEN- (โคเฮน) แฮร์มันน์ (1842 1918) ปราชญ์ชาวเยอรมัน ผู้ก่อตั้งและตัวแทนที่โดดเด่นที่สุดของโรงเรียน Marburg แห่ง neo-Kantianism ผลงานสำคัญ: 'ทฤษฎีประสบการณ์ของคานท์' (พ.ศ. 2428), 'เหตุผลของกานต์ด้านจริยธรรม' (พ.ศ. 2420), 'เหตุผลด้านสุนทรียศาสตร์ของคานท์' (พ.ศ. 2432), 'ตรรกะ… ...

    กันต์ อิมมานูเอล- เส้นทางชีวิตและงานเขียนของ Kant Immanuel Kant เกิดที่ Königsberg (ปัจจุบันคือ Kaliningrad) ในปรัสเซียตะวันออกในปี 1724 พ่อของเขาเป็นนักขี่ม้าและแม่ของเขาเป็นแม่บ้าน ลูกหกคนของพวกเขาไม่ได้อยู่จนโต กันต์นึกถึงพ่อแม่ด้วย ... ... ปรัชญาตะวันตกตั้งแต่กำเนิดจนถึงปัจจุบัน

    ปรัชญาสำคัญของคานท์: หลักคำสอนของความสามารถ- (La philosophie critique de Kant: Doctrines des facultes, 1963) โดย Deleuze อธิบายวิธีการเหนือธรรมชาติในบทนำ Deleuze ตั้งข้อสังเกตว่า Kant เข้าใจปรัชญาในฐานะศาสตร์แห่งความสัมพันธ์ของความรู้ทั้งหมดกับเป้าหมายที่จำเป็น... ... ประวัติศาสตร์ปรัชญา: สารานุกรม

    หลักการฟาร์ม- หลักการพื้นฐานของทัศนศาสตร์เรขาคณิต (ดู ทัศนศาสตร์ทางเรขาคณิต) รูปแบบที่ง่ายที่สุดของ F. p. คือการยืนยันว่ารังสีของแสงมักจะแพร่กระจายในช่องว่างระหว่างจุดสองจุดตามเส้นทางซึ่งเวลาผ่านไปน้อยกว่า ... สารานุกรมแห่งสหภาพโซเวียตผู้ยิ่งใหญ่

    อัลกอริธึมของ Dijkstra เป็นอัลกอริธึมกราฟที่คิดค้นโดยนักวิทยาศาสตร์ชาวดัตช์ Edsger Dijkstra ในปี 1959 ค้นหาเส้นทางที่สั้นที่สุดจากจุดยอดจุดหนึ่งของกราฟไปยังจุดอื่นๆ ทั้งหมด อัลกอริทึมทำงาน สำหรับกราฟที่ไม่มีขอบของน้ำหนักติดลบเท่านั้น

    พิจารณาการดำเนินการของอัลกอริทึมในตัวอย่างกราฟที่แสดงในรูป

    ให้ต้องหาระยะทางที่สั้นที่สุดจากจุดยอดที่ 1 ถึงจุดอื่นๆ ทั้งหมด

    วงกลมระบุจุดยอด เส้นระบุเส้นทางระหว่างพวกเขา (ขอบของกราฟ) ตัวเลขของจุดยอดระบุไว้ในวงกลม "ราคา" - ความยาวของเส้นทาง - ระบุไว้เหนือขอบ ถัดจากจุดยอดแต่ละจุด จะมีป้ายกำกับสีแดง - ความยาวของเส้นทางที่สั้นที่สุดไปยังจุดยอดนี้จากจุดยอด 1

    ขั้นแรก. พิจารณาขั้นตอนในอัลกอริทึมของ Dijkstra สำหรับตัวอย่างของเรา จุดยอด 1 มีป้ายกำกับขั้นต่ำ จุดยอด 2, 3 และ 6 คือจุดใกล้เคียง

    เพื่อนบ้านคนแรกของจุดยอด 1 ในทางกลับกันคือจุดยอด 2 เนื่องจากความยาวของเส้นทางไปนั้นน้อยที่สุด ความยาวของเส้นทางไปผ่านจุดยอด 1 เท่ากับผลรวมของค่าฉลากของจุดยอด 1 และความยาวของขอบที่ไปจากที่ 1 ถึง 2 นั่นคือ 0 + 7 = 7 ซึ่งน้อยกว่า เลเบลปัจจุบันของจุดยอด 2, อินฟินิตี้ ดังนั้นเลเบลใหม่ของจุดยอดที่ 2 คือ 7

    เราทำการดำเนินการที่คล้ายกันกับเพื่อนบ้านอีกสองคนของจุดสุดยอดที่ 1 - ที่ 3 และที่ 6

    ตรวจสอบเพื่อนบ้านทั้งหมดของโหนด 1 ระยะทางต่ำสุดในปัจจุบันไปยังจุดสูงสุด 1 ถือเป็นที่สิ้นสุดและไม่ต้องแก้ไข (ข้อเท็จจริงที่ว่าเป็นกรณีนี้ได้รับการพิสูจน์ครั้งแรกโดย E. Dijkstra) ขีดฆ่าออกจากกราฟเพื่อทำเครื่องหมายว่ามีการเยี่ยมชมจุดยอดนี้แล้ว

    ขั้นตอนที่สอง. ขั้นตอนอัลกอริทึมซ้ำแล้วซ้ำอีก เราพบจุดยอดที่ "ใกล้ที่สุด" ของจุดยอดที่ไม่มีใครเข้าชมอีกครั้ง นี่คือจุดยอด 2 ที่มีป้ายกำกับ 7

    อีกครั้งเราพยายามลดป้ายกำกับเพื่อนบ้านของจุดสุดยอดที่เลือกโดยพยายามผ่านจุดสุดยอดที่ 2 เพื่อนบ้านของ Vertex 2 คือจุดยอด 1, 3 และ 4

    เพื่อนบ้านคนแรก (ตามลำดับ) ของจุดยอด 2 คือจุดยอด 1 แต่มีคนเข้าชมแล้ว ดังนั้นเราจึงไม่ทำอะไรกับจุดยอดที่ 1

    เพื่อนบ้านถัดไปของจุดยอด 2 คือจุดยอด 3 เนื่องจากมีป้ายกำกับขั้นต่ำของจุดยอดที่ทำเครื่องหมายว่าไม่ได้เยี่ยมชม หากคุณผ่าน 2 ความยาวของเส้นทางดังกล่าวจะเท่ากับ 17 (7 + 10 = 17) แต่ป้ายกำกับปัจจุบันของจุดยอดที่สามคือ 9 ซึ่งน้อยกว่า 17 ดังนั้นป้ายกำกับจึงไม่เปลี่ยนแปลง

    เพื่อนบ้านของจุดยอด 2 อีกตัวคือจุดยอด 4 หากคุณผ่านจุดยอดที่ 2 ความยาวของเส้นทางดังกล่าวจะเท่ากับผลรวมของระยะทางที่สั้นที่สุดไปยังจุดยอดที่ 2 และระยะห่างระหว่างจุดยอด 2 และ 4 นั่นคือ , 22 (7 + 15 = 22) . ตั้งแต่ 22<, устанавливаем метку вершины 4 равной 22.

    มีการดูเพื่อนบ้านของจุดยอด 2 ทั้งหมดแล้วเราหยุดระยะห่างและทำเครื่องหมายว่าเยี่ยมชมแล้ว

    ขั้นตอนที่สาม. เราทำซ้ำขั้นตอนของอัลกอริทึมโดยเลือกจุดยอด 3 หลังจาก "ประมวลผล" เราจะได้ผลลัพธ์ดังต่อไปนี้:

    ขั้นตอนถัดไป. เราทำซ้ำขั้นตอนของอัลกอริทึมสำหรับจุดยอดที่เหลือ ซึ่งจะเป็นจุดยอด 6, 4 และ 5 ตามลำดับ

    เสร็จสิ้นการดำเนินการอัลกอริทึม. อัลกอริทึมจะสิ้นสุดลงเมื่อไม่สามารถประมวลผลจุดยอดได้อีก ในตัวอย่างนี้ จุดยอดทั้งหมดจะถูกขีดฆ่า แต่ถือเป็นความผิดพลาดที่จะถือว่านี่เป็นกรณีตัวอย่างใดๆ - จุดยอดบางจุดอาจไม่ถูกขีดฆ่าหากไม่สามารถเข้าถึงได้ กล่าวคือ ถ้ากราฟถูกตัดการเชื่อมต่อ ผลลัพธ์ของอัลกอริทึมสามารถมองเห็นได้ในรูปสุดท้าย: เส้นทางที่สั้นที่สุดจากจุดยอด 1 ถึง 2 คือ 7 ถึง 3 คือ 9 ถึง 4 คือ 20 ถึง 5 คือ 20 ถึง 6 คือ 11

    การใช้อัลกอริทึมในภาษาการเขียนโปรแกรมต่างๆ:

    C++

    #รวม "stdafx.h" #include ใช้เนมสเปซ std; ค่าคงที่ V=6; // อัลกอริธึมของ Dijkstra เป็นโมฆะ Dijkstra(int GR[V][V], int st) ( int distance[V], count, index, i, u, m=st+1; bool visit[V]; for (i= 0 ฉัน "< "<> "; cin>>start; Dijkstra(GR, start-1); system("pause>>void"); )

    ปาสกาล

    โปรแกรม DijkstraAlgorithm; ใช้; constV=6; inf=100000; พิมพ์ vector=array ของจำนวนเต็ม; 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)); (อัลกอริทึมของ Dijkstra) ขั้นตอน Dijkstra(GR: อาร์เรย์ของจำนวนเต็ม; st: จำนวนเต็ม); var count, index, i, u, m, min: จำนวนเต็ม; ระยะทาง: เวกเตอร์; เยี่ยมชม: อาร์เรย์บูลีน; เริ่มต้น:=st; สำหรับ i:=1 ถึง V ทำระยะทางเริ่มต้น[i]:=inf; เยี่ยมชม[i]:=เท็จ; จบ; ระยะทาง:=0; สำหรับ count:=1 ถึง V-1 เริ่มต้น min:=inf; สำหรับ i:=1 ถึง V ทำถ้า (ไม่ได้เยี่ยมชม[i]) และ (ระยะทาง[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) และ (ระยะทาง[u]<>inf) และ (ระยะทาง[u]+GR inf แล้ว writeln(m," > ", i," = ", distance[i]) อื่น writeln(m," > ", i," = ", "เส้นทางไม่พร้อมใช้งาน"); จบ; (บล็อกโปรแกรมหลัก) เริ่ม clrscr; write("โหนดเริ่มต้น >> "); อ่าน (เริ่ม); Dijkstra(GR, เริ่ม); จบ.

    Java

    นำเข้า java.io.BufferedReader; นำเข้า java.io.IOException; นำเข้า java.io.InputStreamReader; นำเข้า java.io.PrintWriter; นำเข้า java.util.ArrayList; นำเข้า java.util.Arrays; นำเข้า java.util.StringTokenizer; โซลูชันคลาสสาธารณะ ( คงที่ส่วนตัว int INF = Integer.MAX_VALUE / 2; int ส่วนตัว n; // จำนวนจุดยอดใน digraph ส่วนตัว int m; // จำนวนส่วนโค้งใน Digraph ส่วนตัว ArrayList adj. //adjacency รายการส่วนตัว ArrayList น้ำหนัก; //น้ำหนักของขอบในไดกราฟไพรเวตบูลีนที่ใช้ //array สำหรับเก็บข้อมูลเกี่ยวกับการผ่านและไม่ผ่าน peaks private int dist; //array เพื่อเก็บระยะห่างจากจุดยอดเริ่มต้น //อาร์เรย์ของบรรพบุรุษที่จำเป็นในการกู้คืนเส้นทางที่สั้นที่สุดจากจุดยอดเริ่มต้นส่วนตัว int pred; การเริ่มต้นภายใน; // จุดเริ่มต้นจุดยอดซึ่งค้นหาระยะทางไปยังส่วนอื่น ๆ ทั้งหมด BufferedReader cin; ศาล PrintWriter ส่วนตัว; ตัวสร้างโทเค็น StringTokenizer ส่วนตัว; // ขั้นตอนในการเริ่มต้นอัลกอริทึมของ Dijkstra จากจุดสุดยอดเริ่มต้น private void dejkstra(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(); ) //เริ่มต้นรายการที่เก็บน้ำหนักของน้ำหนักขอบ = new ArrayList[n]; สำหรับ (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.*; นำเข้า java.util.*; คลาสสาธารณะ Dijkstra ( Graph.Edge สุดท้ายแบบคงที่ส่วนตัว GRAPH = ( Graph.Edge ใหม่ ("a", "b", 7), Graph.Edge ใหม่ ("a", "c", 9), Graph.Edge ใหม่ ( "a", "f", 14), new Graph.Edge("b", "c", 10), new Graph.Edge("b", "d", 15), new Graph.Edge("c "," d ", 11), ใหม่ Graph.Edge ("c", "f", 2), Graph.Edge ใหม่ ("d", "e", 6) ใหม่ Graph.Edge ("e", "f", 9), ); สตริงสุดท้ายคงที่ส่วนตัว START = "a"; สตริงสุดท้ายคงที่ส่วนตัว END = "e"; โมฆะคงที่สาธารณะหลัก (สตริง args) ( กราฟ g = กราฟใหม่ (กราฟ); g.dijkstra (START); g.printPath(END); //g.printAllPaths(); ) ) class Graph ( แผนที่สุดท้ายส่วนตัว กราฟ; // การแมปชื่อจุดยอดกับวัตถุจุดสุดยอด สร้างขึ้นจากชุดขอบ /** ขอบหนึ่งของกราฟ (ใช้โดยตัวสร้างกราฟเท่านั้น) */ คลาสสแตติกสาธารณะ Edge (สตริงสุดท้ายสาธารณะ v1, v2; int dist สาธารณะสุดท้าย; ขอบสาธารณะ(String v1, String v2, int dist) ( this.v1 = v1; this.v2 = v2; this.dist = dist; ) ) /** จุดยอดหนึ่งจุดของกราฟ พร้อมด้วยการแมปไปยังจุดยอดที่อยู่ใกล้เคียง */ คลาสสแตติกสาธารณะ Vertex ใช้ Comparable (ชื่อสตริงสุดท้ายสาธารณะ public int dist = Integer.MAX_VALUE; // MAX_VALUE ถือว่าเป็นอินฟินิตี้สาธารณะ Vertex ก่อนหน้า = null; แผนที่สุดท้ายสาธารณะ เพื่อนบ้าน = HashMap ใหม่<>(); จุดยอดสาธารณะ (ชื่อสตริง) ( this.name = ชื่อ; ) โมฆะส่วนตัว printPath() ( if (นี้ == this.previous) ( System.out.printf("%s", this.name); ) else if ( this.previous == null) ( System.out.printf("%s(unreached)", this.name); ) อื่น ( this.previous.printPath(); System.out.printf(" -> %s( %d)", this.name, this.dist); ) ) public int comparisonTo(Vertex other) ( return Integer.compare(dist, other.dist); ) ) /** สร้างกราฟจากชุดของขอบ * / กราฟสาธารณะ (ขอบขอบ) ( กราฟ = ใหม่ HashMap<>(ขอบ.ความยาว); // ผ่านไปหนึ่งครั้งเพื่อค้นหาจุดยอดทั้งหมดสำหรับ (Edge e: ขอบ) ( if (!graph.containsKey(e.v1)) graph.put(e.v1, new Vertex(e.v1)); if (!graph. hasKey(e.v2)) graph.put(e.v2, new Vertex(e.v2)); ) // ส่งผ่านอื่นเพื่อกำหนดจุดยอดที่อยู่ใกล้เคียงสำหรับ (Edge e: ขอบ) ( 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("Graph doesn't มีจุดยอดเริ่มต้น \"%s\"\n", startName); return; ) แหล่ง Vertex สุดท้าย = graph.get (startName); NavigableSet q = TreeSet ใหม่<>(); // set-up จุดยอดสำหรับ (Vertex v: graph.values()) ( v.previous = v == source ? source: null; v.dist = v == source ? 0: Integer.MAX_VALUE; q.add( v); ) dijkstra(q); ) /** การใช้อัลกอริทึมของ dijkstra โดยใช้ไบนารีฮีป */ private void dijkstra(final NavigableSet q) ( Vertex u, v; while (!q.isEmpty()) ( u = q.pollFirst(); // จุดยอดที่มีระยะทางสั้นที่สุด (การวนซ้ำครั้งแรกจะคืนค่าแหล่งที่มา) if (u.dist == Integer.MAX_VALUE) แตก; // เราสามารถละเว้น u (และจุดยอดอื่น ๆ ที่เหลือ) เนื่องจากไม่สามารถเข้าถึงได้ // ดูระยะทางไปยังเพื่อนบ้านแต่ละคนสำหรับ (Map.Entry a: u.neighbours.entrySet()) ( v = a.getKey(); // เพื่อนบ้านในการวนซ้ำนี้ครั้งสุดท้าย int 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(); } } }

    #รวม #รวม #รวม //#define BIG_EXAMPLE typedef struct node_t node_t, *heap_t; typedef struct edge_t edge_t; struct edge_t ( node_t *nd; /* เป้าหมายของ edge */ edge_t *sibling;/* สำหรับรายการที่เชื่อมโยงอย่างเดียว */ int len; /* edge cost */ ); struct node_t ( edge_t *edge; /* รายการที่เชื่อมโยงอย่างเดียวของ edge */ node_t *via; /* โดยที่โหนดก่อนหน้าอยู่ในเส้นทางที่สั้นที่สุด */ double dist; /* ระยะทางจากโหนดต้นทาง */ ชื่อถ่าน; /* the, er , ชื่อ */ int heap_idx; /* เชื่อมโยงไปยังตำแหน่งฮีปเพื่ออัพเดตระยะทาง */ ); /* --- การจัดการขอบ --- */ #ifdef BIG_EXAMPLE # กำหนด BLOCK_SIZE (1024 * 32 - 1) #else # กำหนด 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() ( สำหรับ (; 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; /* upheap */ สำหรับ (; i > 1 && nd->dist< heap->ระยะทาง; i = j) (heap[i] = heap[j])->heap_idx = i; กอง[i] = nd; nd->heap_idx = ผม; สำหรับ (ผม = 1; ผม< heap_len && (j = i * 2) <= heap_len; i = j) { if (j < heap_len && heap[j]->dist > heap->dist) j++; ถ้า (heap[j]->dist >= tmp->dist) แตก; (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())) สำหรับ ( e = lead->edge; e; e = e->sibling) set_dist(e->nd, lead, lead->dist + e->len); ) เป็นโมฆะ show_path(node_t *nd) ( if (nd-> ผ่าน == nd) printf("%s", nd->name); else if (!nd->via) printf("%s(unreached)", nd->name); else ( show_path(nd-> ผ่าน); printf("-> %s(%g) ", nd->name, nd->dist); ) ) int main(void) ( #ifndef BIG_EXAMPLE int i; # กำหนด N_NODES ("f" - " a" + 1) node_t *nodes = calloc(sizeof(node_t), N_NODES); สำหรับ (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); $neighbours[$edge] = array("end" => $edge, "ต้นทุน" => $edge); ) $จุดยอด = array_unique($จุดยอด); foreach ($vertices เป็น $vertex) ( $dist[$vertex] = INF; $previous[$vertex] = NULL; ) $dist[$source] = 0; $Q = $จุดยอด; while (count($Q) > 0) ( // TODO - ค้นหาวิธีที่เร็วกว่าในการรับขั้นต่ำ $min = INF; foreach ($Q เป็น $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

    จากคอลเลกชันนำเข้า namedtuple คิวจาก pprint นำเข้า pprint เป็น pp inf = float("inf") Edge = namedtuple("Edge", "start, end, cost") คลาส Graph(): def __init__(self, edge): self .edges = edge2 = self.vertices = set(ผลรวม (( สำหรับ e ใน edge2), )) def dijkstra (ตัวเอง, แหล่งที่มา, ปลายทาง): ยืนยันแหล่งที่มาใน self.vertices dist = (จุดยอด: inf สำหรับจุดสุดยอดใน self.vertices ) ก่อนหน้า = (จุดยอด: ไม่มีสำหรับจุดยอดในจุดยอด) dist = 0 q = self.vertices.copy() เพื่อนบ้าน = (จุดยอด: set() สำหรับจุดยอดในจุดยอดด้วยตนเอง) สำหรับจุดเริ่มต้น จุดสิ้นสุด ต้นทุนในตัวเอง ขอบ: Neighbors.add((จบ, ราคา)) #pp(เพื่อนบ้าน) ในขณะที่ q: u = นาที (q, คีย์=แลมบ์ดา จุดยอด: dist) q.remove(u) ถ้า dist[u] == inf หรือ u = = ปลายทาง: แบ่งสำหรับ v ต้นทุนในเพื่อนบ้าน[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"]

    บทความที่คล้ายกัน
     
    หมวดหมู่