두 평행선 사이의 거리 결정. 그래프

  • 12.12.2021

DISTANCE, 거리, 참조. 1. 두 점을 나누는 공간, 무언가 사이의 간격. 직선상의 두 점 사이의 최단 거리. 2km의 거리에서 우리에게서 삽니다. "사령관은 그들이 가능한 한 가까이 오도록 허용했습니다 ... Ushakov의 설명 사전

거리- 명사, p., uptr. 종종 형태학: (아니) 뭐? 거리, 뭐? 거리, (참조) 무엇? 거리보다? 거리, 무엇에 대해? 거리에 대해; pl. 무엇? 거리, (아니) 뭐? 거리, 뭐? 거리, (참조) 무엇? 거리보다? 거리 ... Dmitriev의 설명 사전

거리- 그래요; 수 두 점, 두 물체 등을 나누는 공간, 누구, 보다 l. 가장 짧은 r. 두 점 사이. R. 집에서 학교까지. 가까운 강으로 이동합니다. 미터의 거리에서 뻗은 손. l을 알다, l을 느끼다 에… … 백과사전

거리- 그래요; 수 또한보십시오. 거리 a) 두 점, 두 물체 등을 분리하는 공간, 누구, 보다 l. 두 점 사이의 최단 거리. 거리 / 집에서 학교까지의 거리. 가까이 ... 다양한 표현의 사전

기하학- 다양한 모양(점, 선, 각도, 2차원 및 3차원 물체), 크기 및 상대적 위치의 특성 연구를 다루는 수학의 한 분야. 교육의 편의를 위해 기하학은 평면과 입체로 세분화됩니다. V… … 콜리어의 백과사전

항해*

항해- 항해부(참조), 나침반과 통나무를 사용하여 바다에서 선박의 위치를 ​​결정하는 방법에 대한 설명을 마무리합니다(참조). 해상에서 선박의 위치를 ​​결정한다는 것은 선박이 현재 위치하는 지점을 지도에 그리는 것을 의미합니다. . . . . F.A. 백과사전 브로크하우스와 I.A. 에프론

코겐- (Cohen) Hermann (1842 1918) 독일 철학자, 설립자이자 신칸트주의의 마르부르크 학파의 가장 저명한 대표자. 주요 저서: '칸트의 경험론'(1885), '칸트의 윤리학 정당화'(1877), '칸트의 미학 정당화'(1889), '논리학 ... ...

칸트 임마누엘- 칸트의 생애와 작품 임마누엘 칸트는 1724년 동프로이센의 쾨니히스베르그(지금의 칼리닌그라드)에서 태어났다. 그의 아버지는 안장인이었고 어머니는 주부였으며 여섯 자녀는 장년까지 살지 못했다. 칸트는 항상 그의 부모를 기억했습니다 ... ... 서양철학의 시작부터 현재까지

칸트의 비판적 철학: 능력에 대한 가르침- (La philosophie critique de Kant: Doctrines des facultes, 1963) 들뢰즈. 도입부에서 초월적 방법을 설명하면서, 들뢰즈는 칸트가 철학을 모든 지식과 본질적 목표 사이의 관계에 대한 과학으로 이해한다는 점에 주목합니다. 철학의 역사: 백과사전

농장 원리- 기하학적 광학의 기본 원리(기하학적 광학 참조). 위상 변이의 가장 간단한 형태는 광선이 통과 시간이 ...보다 짧은 경로를 따라 두 점 사이의 공간에서 항상 전파된다는 진술입니다. 위대한 소비에트 백과사전

그림에서 점선의 경로는 실선의 경로보다 짧습니다. 이제 해상 경로의 예에 대해 조금 더 자세히 설명합니다.

일정한 방향으로 항해하면 지표면에서 선박의 이동 궤적은 수학에서 말하는 곡선이 됩니다 대수나선.

탐색에서 이 복잡한 이중 곡률 선은 록소드로미아, 그리스어에서 번역하면 "비스듬한 실행"을 의미합니다.

그러나 지구상의 두 점 사이의 최단 거리는 대원의 호를 따라 측정됩니다.

대원호는 지구 표면과 지구 중심을 통과하는 평면의 교차점에서 공으로 간주하여 궤적으로 얻습니다.

탐색에서 대원이라고 합니다. 정형외과, 번역에서 "직진"을 의미합니다. 정형 교정술의 두 번째 특징은 다른 각도에서 자오선을 가로지르는 것입니다(그림 29).

하프 트랙과 orthodrome의 지구 표면에 있는 두 지점 사이의 거리 차이는 큰 바다를 횡단하는 경우에만 실질적으로 중요합니다.

정상적인 조건에서 이 차이는 무시되고 수영은 일정한 코스로 수행됩니다. 록소드롬을 따라.

방정식을 유도하기 위해 록소드롬을 취합니다(그림 30, ) 두 점 그리고 V,그 사이의 거리는 기본적으로 작습니다. 자오선과 평행선을 그리면 기본 직각 구형 삼각형을 얻습니다. 알파벳.이 삼각형에서 자오선과 평행선의 교점이 이루는 각은 직각이고, NAB선박의 표제와 동일 K. Cathet 처럼자오선의 한 부분을 나타내며 다음과 같이 표현할 수 있습니다.

어디 아르 자형 - 공으로 간주되는 지구의 반지름;

Δφ - 기본 위도 증분(위도 차이).

카테투스 SV평행 호 세그먼트를 나타냅니다.

어디서 r - 평행 반경;

Δλ - 경도의 기본 차이.

삼각형 OO 1 C에서 당신은 그것을 찾을 수 있습니다

그런 다음 다리의 최종 형태에서 SV다음과 같이 표현할 수 있습니다.

기본 구면 삼각형 취하기 알파벳플랫, 쓰기

컷 후 아르 자형 기본적으로 작은 좌표 증분을 무한소로 대체하면

φ 1, λ 1 ~ φ 2 범위에서 결과 식을 통합합시다. λ 2 tgK 값을 상수로 가정:

오른쪽에는 테이블 형식의 적분이 있습니다. 그 값을 대입 한 후 공에 대한 loxodromy 방정식을 얻습니다.

이 방정식을 분석하면 다음과 같은 결론이 나옵니다.

코스 0과 180 °에서 loxodrome은 자오선의 큰 원호로 바뀝니다.

90 및 270 °의 과정에서 록소드롬은 평행선과 일치합니다.

록소드롬은 각 평행선을 한 번만 교차하고 각 자오선을 수없이 교차합니다. 저것들. 극에 나선형으로 접근하면 도달하지 않습니다.

일정한 항로, 즉 록소드롬(loxodrome)에서 항해하는 것은 지구상의 두 지점 사이의 최단 거리가 아니지만 항해자에게 상당한 편의를 제공합니다.

해상 항해도에 대한 요구 사항은 록소드롬을 따라 항해하는 이점과 그 방정식의 분석 결과를 기반으로 다음과 같이 공식화할 수 있습니다.

1. 일정한 각도로 자오선을 가로지르는 Loxodromia는 직선으로 그려야 합니다.

2. 지도 작성에 사용되는 지도 제작 투영은 코스, 방위 및 각도가 지상의 값과 일치하도록 등각이어야 합니다.

3. 코스 라인 0, 90, 180 ° 및 270 °와 같은 자오선 및 평행선은 서로 수직인 직선이어야 합니다.

지구 표면의 주어진 두 점 사이의 최단 거리는 공으로 간주하여 이러한 점을 지나는 대원의 호 중 더 작은 것입니다. 자오선이나 적도를 따라가는 선박의 경우 외에도 정교회는 자오선과 다른 각도로 교차합니다. 따라서 이러한 곡선을 따르는 선박은 항상 항로를 변경해야 합니다. 실제로, 자오선과 일정한 각도를 만들고 메르카토르 투영법의 지도에 직선 - loxodromy로 표시되는 코스를 따르는 것이 더 편리합니다. 그러나 먼 거리에서 orthodrome과 loxodrome의 길이 차이는 상당한 값에 도달합니다. 따라서 이러한 경우 정교회가 계산되고 loxodrome이 수영하는 중간 지점이 표시됩니다.

나열된 요구 사항을 충족하는 지도 제작 투영법은 1569년 네덜란드 지도 제작자 Gerard Kramer(Mercator)에 의해 제안되었습니다. 제작자를 기리기 위해 투영법 이름이 명명되었습니다. 메르카토리얼.

그리고 더 흥미로운 정보를 얻고 싶은 사람은 더 많은 것을 알아내십시오. 원본 기사는 사이트에 있습니다 InfoGlaz.rf이 사본을 만든 기사의 링크는 다음과 같습니다.

(도형 기하학)
  • CD(CXDX, C2D2)포인트로 표현 C5 = D5 А5В5같음...
    (도형 기하학)
  • 두 평행 평면 사이의 거리 결정
    일반 위치에서 두 평행 평면 사이의 거리 결정 01 | 엑스프로젝터의 위치로 변환된 동일한 두 평면 사이의 거리를 결정하는 작업으로 줄이는 것이 편리합니다. 이 경우 평면 사이의 거리는 직선 사이의 수직선으로 정의되며 ...
    (도형 기하학)
  • 두 개의 교차 직선 사이의 거리 결정
    두 교차선 사이의 최단 거리를 결정하려면 투영 평면 시스템을 두 번 변경해야 합니다. 이 문제를 풀 때 직선 CD(CXDX, C2D2)포인트로 표현 C5 = D5(그림 198). 이 지점에서 투영까지의 거리 А5В5같음...
    (도형 기하학)
  • 교차하는 두 직선 사이의 각도
    이것은 데이터에 평행한 두 개의 교차 선 사이의 각도입니다. 따라서 이 작업은 이전 작업과 유사합니다. 그것을 해결하려면 임의의 점을 취하고 주어진 교차 직선에 평행 한 두 개의 직선을 그리고 투영 변환을 사용하여 원하는 각도를 결정해야합니다 ...
    (기하학의 기초. 짧은 과정과 문제 모음.)
  • 두 평행선 사이의 거리 결정
    이 문제는 투영 평면의 이중 교체로 해결됩니다. 마지막 단계에서 투영 평면 중 하나는 교차선 중 하나에 수직이어야 합니다. 그런 다음 그들 사이의 최단 거리는 다른 교차 직선에 대한 수직 세그먼트의 크기에 의해 결정됩니다(그림 199) ....
    (도형 기하학)
  • Dijkstra 알고리즘은 1959년 네덜란드 과학자 Edsger Dijkstra가 발명한 그래프 알고리즘입니다. 그래프의 정점 중 하나에서 다른 모든 정점까지의 최단 경로를 찾습니다. 알고리즘 작동 음수 가중치의 간선이 없는 그래프에만 해당합니다.

    그림에 표시된 그래프의 예를 사용하여 알고리즘의 실행을 고려해 보겠습니다.

    첫 번째 꼭짓점에서 다른 모든 꼭짓점까지의 최단 거리를 구해야 합니다.

    원은 꼭짓점, 선 - 그 사이의 경로(그래프의 가장자리)를 나타냅니다. 정점의 수는 원으로 표시되고 "가격"은 경로의 길이인 가장자리 위에 표시됩니다. 각 정점 옆에는 정점 1에서 이 정점까지의 최단 경로 길이인 빨간색 레이블이 있습니다.

    첫 번째 단계... 우리의 예를 위해 Dijkstra 알고리즘의 한 단계를 고려해 봅시다. 꼭짓점 1에는 최소 레이블이 있고 그 이웃은 꼭짓점 2, 3, 6입니다.

    정점 1의 첫 번째 이웃은 정점 2에 대한 경로 길이가 최소이기 때문에 정점 2입니다. 꼭짓점 1을 통과하는 경로의 길이는 꼭짓점 1의 레이블 값과 1번째에서 2번째로 가는 가장자리 길이의 합과 같습니다. 즉, 0 + 7 = 7입니다. 이것은 더 적습니다. 정점 2의 현재 레이블, 무한대보다 크므로 두 번째 정점의 새 레이블은 7입니다.

    우리는 첫 번째 정점의 다른 두 이웃인 세 번째와 여섯 번째 정점과 비슷한 작업을 수행합니다.

    정점 1의 모든 이웃이 확인됩니다. 피크 1까지의 현재 최소 거리는 최종적인 것으로 간주되며 수정 대상이 아닙니다(이것이 실제로 그렇게 되었다는 사실은 E. Dijkstra에 의해 처음으로 입증되었습니다). 이 정점을 방문했음을 표시하기 위해 그래프에서 삭제해 보겠습니다.

    두번째 단계... 알고리즘 단계가 반복됩니다. 방문하지 않은 정점의 "가장 가까운"을 다시 찾습니다. 이것은 꼭짓점 2이고 레이블은 7입니다.

    우리는 다시 선택된 정점의 이웃 레이블을 줄이려고 시도하고 두 번째 정점을 통과하려고 시도합니다. 정점 2의 이웃은 정점 1, 3, 4입니다.

    꼭짓점 2의 첫 번째 (순서대로) 이웃은 꼭짓점 1입니다. 하지만 이미 방문했기 때문에 첫 번째 꼭짓점에 대해서는 아무 것도 하지 않습니다.

    정점 2의 다음 이웃은 정점 3입니다. 방문하지 않은 것으로 표시된 정점의 최소 레이블이 있기 때문입니다. 2를 통해 이동하면 그러한 경로의 길이는 17(7 + 10 = 17)과 같습니다. 그러나 세 번째 꼭짓점의 현재 레이블은 17보다 작은 9이므로 레이블이 변경되지 않습니다.

    꼭짓점 2의 또 다른 이웃은 꼭짓점 4입니다. 두 번째 꼭짓점을 통해 이동하면 그러한 경로의 길이는 두 번째 꼭짓점까지의 최단 거리와 꼭짓점 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++

    #include "stdafx.h" #include 네임 스페이스 표준 사용; 상수 정수 V = 6; // Dijkstra의 알고리즘 void Dijkstra (int GR [V] [V], int st) (int distance [V], count, index, i, u, m = st + 1; bool 방문 [V]; for (i = 0; 나는 "< "<> "; cin >> 시작; Dijkstra(GR, 시작-1); 시스템(" 일시 중지 >> 무효 ");)

    파스칼

    프로그램 다익스트라 알고리즘; crt를 사용합니다. 상수 V = 6; 인프 = 100000; 유형 벡터 = 정수 배열; var 시작: 정수; 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: 정수); 변수 개수, 인덱스, i, u, m, 최소값: 정수; 거리: 벡터; 방문: 부울 배열; 시작 m: = st; i의 경우: = 1에서 V 시작 거리 [i]: = inf; 방문 [i]: = 거짓; 끝; 거리: = 0; 카운트의 경우: = 1에서 V-1까지 시작 min: = inf; for i: = 1 ~ V do if (방문하지 않은 [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 then writeln (m, ">", i, "=", 거리 [i]) else writeln (m, ">", i, "=", "경로를 사용할 수 없음"); 끝; (주 프로그램 블록) clrscr 시작; write("정점 시작 >>"); 읽기(시작); 다익스트라(GR, 시작); 끝.

    자바

    가져오기 java.io.BufferedReader; 가져오기 java.io.IOException; 가져오기 java.io.InputStreamReader; 가져오기 java.io.PrintWriter; 가져오기 java.util.ArrayList; 가져오기 java.util.Arrays; 가져오기 java.util.StringTokenizer; public class Solution (private static int INF = Integer.MAX_VALUE / 2; private int n; // digraph의 꼭짓점 수 private int m; // digraph private ArrayList의 호 수 조정; // 인접 목록 private ArrayList 무게; // digraph에서 에지의 가중치 사용된 private 부울; // 전달된 정점과 전달되지 않은 정점에 대한 정보를 저장하기 위한 배열 private int dist; // 시작 정점으로부터의 거리를 저장하기 위한 배열 // 시작 정점에서 최단 경로를 복원하는 데 필요한 조상 배열 private int pred; 정수 시작; // 다른 모든 것들까지의 거리를 구하는 시작 정점 private BufferedReader cin; 개인 PrintWriter cout; 개인 StringTokenizer 토크나이저; // 시작 정점에서 Dijkstra 알고리즘을 시작하는 절차 private void dejkstra (int s) (dist [s] = 0; // 시작 정점까지의 최단 거리는 0 for (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]; (int 나는 = 0; 나는< 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.*; public class Dijkstra(비공개 정적 최종 Graph.Edge GRAPH = (new Graph.Edge("a", "b", 7), new Graph.Edge("a", "c", 9), new Graph.Edge( "a", "f", 14), 새 Graph.Edge("b", "c", 10), 새 Graph.Edge("b", "d", 15), 새 Graph.Edge("c "," d ", 11), 새 Graph.Edge(" c "," f ", 2), 새 Graph.Edge(" d "," e ", 6), 새 Graph.Edge(" e ", "f", 9),), 비공개 정적 최종 문자열 START = "a", 비공개 정적 최종 문자열 END = "e", 공개 정적 무효 메인(문자열 인수)(그래프 g = 새로운 그래프(GRAPH), g.dijkstra (START); g.printPath(END); //g.printAllPaths();)) 클래스 그래프(개인 최종 지도 그래프; // 정점 이름을 정점 객체에 매핑, Edge 집합에서 빌드 / ** 그래프의 한 모서리(그래프 생성자에서만 사용) * / 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;)) / ** 그래프의 한 꼭짓점, 인접 꼭짓점에 대한 매핑이 완료됨 * / 공용 정적 클래스 Vertex는 Comparable을 구현합니다. (public final String name; public int dist = Integer.MAX_VALUE; // MAX_VALUE는 무한대로 가정됨 public Vertex previous = 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);)) / ** 에지 세트에서 그래프 작성 * / 공개 그래프(가장자리 가장자리)(그래프 = 새로운 HashMap<>(가장자리.길이); // 모든 정점을 찾기 위한 한 번의 패스 for (Edge e: edge) (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: edge) (graph.get (e.v1))에 대한 인접 정점을 설정하기 위한 또 다른 패스. Neighbors.put (graph.get(e.v2), e.dist); //graph.get(e.v2).neighbors.put(graph.get(e.v1), e.dist); // 또한 무방향 그래프에 대해 수행)) / ** 지정된 소스 정점을 사용하여 dijkstra를 실행합니다. * / public void dijkstra (String startName) (if (!graph.containsKey (startName)) (System.err.printf ("Graph does" t 포함 시작 정점 \ "% s \" \ n ", startName), 반환,) 최종 정점 소스 = 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)에 대한 설정 정점 추가 ( v);) dijkstra (q); ) / ** 바이너리 힙을 사용한 dijkstra "s 알고리즘의 구현. * / Private void dijkstra(최종 NavigableSet q) (Vertex u, v; while (! q.isEmpty ()) (u = q.pollFirst (); // 가장 짧은 거리의 정점(첫 번째 반복은 소스를 반환함) if (u.dist == Integer.MAX_VALUE) break; // 도달할 수 없기 때문에 u(및 다른 나머지 정점)를 무시할 수 있습니다. // (Map.Entry에 대한 각 이웃까지의 거리를 봅니다. a: u.neighbors.entrySet()) (v = a.getKey(); // 이 반복의 이웃 final int alternateDist = 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(); } } }

    #포함하다 #포함하다 #포함하다 // # BIG_EXAMPLE 정의 typedef struct node_t node_t, * heap_t; typedef 구조체 edge_t edge_t; struct edge_t (node_t * nd; / * 이 에지의 대상 * / edge_t * 형제; / * 단일 연결 리스트의 경우 * / int len; / * 에지 비용 * /); struct node_t (edge_t * edge; / * 에지의 단일 연결 목록 * / node_t * via; / * 이전 노드가 최단 경로에 있는 경우 * / double dist; / * 원래 노드로부터의 거리 * / char 이름; / * the, er , name * / 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 -> 형제 = 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; / * upheap * / for (; i> 1 && nd-> dist< heap->거리; i = j) (힙 [i] = 힙 [j]) -> heap_idx = i; 힙 [i] = nd; nd-> heap_idx = 나; ) node_t * pop_queue () (node_t * nd, * tmp; int i, j; if (! heap_len) return 0; / * 선행 요소를 제거하고 꼬리 요소를 거기에서 당겨서 downheap * / nd = heap; tmp = heap; for (나는 = 1; 나는< heap_len && (j = i * 2) <= heap_len; i = j) { if (j < heap_len && heap[j]->dist> 힙-> dist) j ++; if (힙 [j] -> dist> = tmp-> dist) break; (힙 [i] = 힙 [j]) -> heap_idx = i; ) 힙 [i] = tmp; tmp-> heap_idx = 나; 반환 nd; ) / * --- 다익스트라 물건; 도달할 수 없는 노드는 대기열에 들어가지 않습니다 --- * / void calc_all (node_t * start) (node_t * lead; edge_t * e; set_dist (start, start, 0); while ((lead = pop_queue ())) for ( e = 리드-> 에지, e, e = e-> 형제) set_dist (e-> nd, 리드, 리드-> 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; # N_NODES 정의("f" - " a "+ 1) node_t * 노드 = 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); $ 이웃 [$ edge] = 배열("end" => $ edge, "cost" => $ edge); ) $ 정점 = array_unique($ 정점); foreach ($ 정점을 $ 정점으로) ($ dist [$ 정점] = INF; $ 이전 [$ 정점] = NULL;) $ dist [$ 소스] = 0; $ Q = $ 정점; while (count ($ Q)> 0) (// TODO - 최소 $ min = 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";


    파이썬

    from collections import namedtuple, queue from pprint import pprint as pp inf = float ("inf") Edge = namedtuple ("Edge", "start, end, cost") class Graph (): def __init __ (self, edge): self .edges = edge2 = self.vertices = set (sum ((for e in edge2),)) def dijkstra (self, source, dest): self.vertices에서 소스를 주장합니다. dist = (vertex: inf for vertex in self. vertices ) 이전 = (정점: self.vertices의 정점에 대해 없음) dist = 0 q = self.vertices.copy () Neighbors = (정점: self.vertices의 정점에 대해 () 설정) 시작, 끝, 자체 비용 . edge: Neighbors.add ((end, cost)) #pp (neighbors) while q: u = min (q, key = 람다 정점: dist) q.remove (u) if 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"]

    칠판에 분필로 두 점을 표시한 후 교사는 어린 학생에게 두 점 사이의 최단 경로를 그리는 작업을 제공합니다.

    생각을 한 학생은 조심스럽게 그들 사이에 구불구불한 선을 그립니다.

    - 이것이 최단거리다! - 선생님이 놀랐다. - 누가 가르쳐줬어?

    - 우리 아빠. 그는 택시 운전사입니다.

    순진한 남학생의 그림은 물론 일화이지만, 그림에서 점선으로 된 호가 있다는 말을 듣는다면 웃지 않겠습니까? 1호는 희망봉에서 호주 남단까지의 최단거리!

    더욱 놀라운 것은 다음과 같은 진술입니다. 2 일본에서 파나마 운하까지의 원형 교차로 루트는 같은 지도에서 그 사이를 잇는 직선보다 짧습니다!

    쌀. 1. 해상지도에서 희망봉에서 호주 남단까지의 최단 경로는 직선("loxodrome")이 아니라 곡선("orthodrome")으로 표시됩니다.


    이 모든 것이 농담처럼 보이지만, 아직까지는 지도 제작자에게 잘 알려진 논쟁의 여지가 없는 진실입니다.




    쌀. 2. 항해도에서 요코하마와 파나마 운하를 연결하는 곡선 경로가 동일한 지점을 연결하는 직선보다 짧다는 것은 놀라운 것 같습니다.


    문제를 명확히 하기 위해 일반적인 지도와 특히 바다 지도에 대해 몇 마디 말해야 할 것입니다. 지구는 구체이기 때문에 종이에 지표면의 일부를 그리는 것은 원칙적으로도 쉽지 않은 일이며, 구면의 어느 부분도 평면에 접히고 부러지지 않고 전개될 수 없다는 것이 알려져 있습니다. 어쩔 수 없이 카드의 불가피한 왜곡을 감수해야 합니다. 지도를 그리는 많은 방법이 발명되었지만 모든 지도에 결함이 없는 것은 아닙니다. 일부는 한 종류의 왜곡이 있고 다른 종류는 다른 종류의 왜곡이 있지만 왜곡이 없는 지도는 전혀 없습니다.

    선원들은 16세기 네덜란드의 옛 지도 제작자이자 수학자의 방법에 따라 그린 지도를 사용합니다. 메르카토르. 이 방법을 "메르카토르 투영법"이라고 합니다. 직사각형 격자로 해상 차트를 쉽게 인식할 수 있습니다. 자오선은 일련의 평행한 직선 형태로 표시됩니다. 위도의 원은 첫 번째에 수직인 직선이기도 합니다(그림 5 참조).

    같은 평행선에 있는 한 항구에서 다른 항구로 가는 최단 경로를 찾고 있다고 상상해 보십시오. 바다에서는 모든 길에 접근할 수 있으며, 그 길이 어떻게 돌아가는지 알면 그곳에서 가장 짧은 길을 따라 여행할 수 있습니다. 우리의 경우 최단 경로가 두 포트가 있는 평행선을 따라 간다고 생각하는 것이 당연합니다. 결국 지도에서는 ​​직선이고 직선보다 짧을 수 있습니다! 그러나 우리는 틀렸습니다. 평행 경로는 결코 최단 경로가 아닙니다.

    실제로: 공의 표면에서 두 점 사이의 가장 짧은 거리는 두 점을 연결하는 큰 원의 호입니다. 그러나 평행선의 원 - 작은 원. 큰 원의 호는 동일한 두 점을 통해 그린 작은 원의 호보다 덜 구부러져 있습니다. 더 큰 반지름은 더 작은 곡률에 해당합니다. 지구상의 두 점 사이의 실을 당기십시오(참조, 그림 3). 평행선을 따라 놓여 있지 않은지 확인하십시오. 뻗어있는 실은 가장 짧은 경로의 확실한 지표이며 지구상의 평행선과 일치하지 않으면 항해도에서 최단 경로는 직선으로 표시되지 않습니다. 평행선의 원이 그러한 평면에 묘사되어 있음을 기억하십시오 직선에 의한 지도, 직선과 일치하지 않는 모든 선, 곡선 .



    쌀. 3. 두 점 사이의 가장 짧은 경로를 찾는 간단한 방법: 지구에서 이 점 사이에 실을 당겨야 합니다.


    이상의 설명을 들으니 항해도에서 최단 경로를 직선이 아닌 곡선으로 그리는 이유가 명확해졌습니다.

    그들은 Nikolaev (현재 10 월) 철도의 방향을 선택할 때 그것을 배치하는 방법에 대한 끝없는 논쟁이 있다고 말합니다. 논쟁의 끝은 문제를 문자 그대로 "직접적으로" 해결한 차르 니콜라스 1세의 개입으로 이루어졌습니다. 그는 상트페테르부르크와 모스크바를 선을 따라 연결했습니다. 이것이 메르카토르 지도에서 이루어졌다면 당황스러운 놀라움으로 밝혀졌을 것입니다. 직선 대신에 도로가 곡선으로 밝혀졌을 것입니다.

    계산을 피하지 않는 사람은 지도에서 곡선으로 표시되는 경로가 우리가 직선으로 간주할 준비가 된 경로보다 실제로 짧다는 것을 간단한 계산으로 확인할 수 있습니다. 우리의 두 항구가 60도선에 있고 60 °의 거리로 분리되어 있습니다. (물론 그러한 두 항구가 실제로 존재하는지 여부는 계산과 관련이 없습니다.)



    쌀. 4. 평행 호를 따라 큰 원의 호를 따라 볼의 점 A와 B 사이의 거리 계산


    그림에서. 4점 오 -지구의 중심, AB -항구가 있는 위도의 원호 A 및 B; V그녀의 60 °. 위도 원의 중심은 한 점에 있습니다. 와 함께중앙에서 상상해보십시오. 영형지구는 큰 원의 동일한 항구 호를 통해 그려집니다. OB = OA = R;그려진 호에 가깝게 지나갈 것입니다. AB,그러나 그녀와 일치하지 않을 것입니다.

    각 호의 길이를 계산해 보겠습니다. 포인트부터 그리고 V위도 60 °에 놓이면 반지름 OA그리고 OV보충하다 OS(지구의 축) 30 °의 각도. 직각 삼각형에서 아소다리 AC (= r),빗변의 절반과 같은 30 °의 반대 각도 JSC;

    수단, r = R / 2호 길이 AB위도 원의 길이의 1/6이고 이 원이 큰 원의 길이의 절반(반지름에 해당)이므로 작은 원의 호 길이는



    이제 동일한 점 사이에 그려진 큰 원의 호 길이(즉, 두 점 사이의 최단 경로)를 결정하려면 각도 값을 알아야 합니다. AOB.처럼 60 ° (작은 원)의 호를 수축하는 것은 동일한 작은 원에 새겨진 정육각형의 측면입니다. 그렇기 때문에 AB = r = R / 2

    직선을 그린 후 외경,연결 센터 영형가운데가 있는 지구 화음 AB,우리는 직각 삼각형을 얻습니다 오다,각도는 어디에 디 -똑바로:

    DA = 1/2 AB 및 OA = R.

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

    여기에서 우리는 다음을 찾습니다(표에 따라).

    = 14 ° 28 ", 5

    따라서

    = 28 ° 57 ".

    이제 킬로미터 단위로 필요한 최단 경로의 길이를 찾는 것이 어렵지 않습니다. 지구의 대원의 1분의 길이가 mo임을 기억하면 계산을 단순화할 수 있습니다.

    우리는 바다 지도에 직선으로 표시된 위도 원의 경로가 3333km이고 지도의 곡선을 따라 큰 원의 경로가 3213km, 즉 120km 짧다는 것을 배웁니다.

    실로 무장하고 손에 지구본이 있으면 도면의 정확성을 쉽게 확인하고 큰 원의 호가 도면에 표시된 대로 실제로 움직이는지 확인할 수 있습니다. 그림에 나와 있습니다. 1 아프리카에서 호주까지의 "직접" 항로는 6020마일이고 "곡선"은 5450마일, 즉 570마일 또는 1050km 단축됩니다. 런던에서 상하이까지 해상 지도의 "직접" 항공 노선은 카스피해를 가로지르는 반면, 실제로 가장 짧은 노선은 상트페테르부르크 북쪽을 운행합니다. 이러한 문제가 시간과 연료를 절약하는 데 어떤 역할을 하는지는 분명합니다.

    항해 시대에 시간이 항상 가치있는 것은 아니 었습니다. "시간"은 아직 "돈"으로 간주되지 않았습니다. 그런 다음 증기선의 출현으로 불필요하게 소비 된 석탄 톤마다 비용을 지불해야합니다. 그렇기 때문에 오늘날 선박은 메르카토리안이 아닌 소위 "중앙" 투영법으로 만들어진 지도를 사용하여 가장 짧은 경로를 따라 안내됩니다. 이 지도에서 큰 원의 호는 직선으로 표시됩니다.

    전직 항해사들은 왜 그런 기만적인 차트를 사용하고 수익성이 없는 경로를 선택했습니까? 옛날에 그들이 해상 차트의 이 특별한 기능에 대해 몰랐다고 생각하는 것은 실수입니다. 물론 그 이유는 이것 때문이 아니라 메르카토르 방식으로 뽑힌 카드들이 불편함과 함께 선원들에게 매우 귀한 혜택을 준다는 사실이다. 이러한 지도는 먼저 등고선의 모서리를 유지하면서 왜곡 없이 지표면의 개별적인 작은 부분을 묘사합니다. 이것은 적도로부터의 거리에 따라 모든 윤곽이 눈에 띄게 늘어진다는 사실과 모순되지 않습니다. 고위도에서는 스트레칭이 너무 중요하여 해상 차트가 그 기능에 익숙하지 않은 사람에게 영감을 줍니다. 대륙의 실제 크기에 대한 완전히 잘못된 생각: 그린란드는 아프리카와 크기가 같고 알래스카는 호주보다 큽니다. , 그린란드는 아프리카보다 15배 작고 알래스카는 그린란드와 함께 호주의 절반 크기입니다. 그러나 카드의 이러한 기능을 잘 알고 있는 선원은 오도될 수 없습니다. 그는 특히 작은 지역 내에서 바다 지도가 자연의 정확한 유사성을 제공하기 때문에 그것들을 참습니다(그림 5).

    그러나 항해 차트는 항해 연습 과제의 해결을 크게 촉진합니다. 항로상의 선박의 항로를 직선으로 표시한 유일한 해도이다. "일정한 경로"로 간다는 것은 항상 한 방향으로, 하나의 확실한 "룸바"를 유지하는 것을 의미합니다. 즉, 모든 자오선을 동일한 각도로 가로지르도록 가는 것입니다. 그러나 이 경로("loxodromia")는 모든 자오선이 서로 평행한 직선인 지도에서만 직선으로 묘사될 수 있습니다. 그리고 지구상에서 위도의 원이 자오선과 직각으로 교차하기 때문에 그러한지도에서 위도의 원은 자오선에 수직 인 직선이어야합니다. 요컨대 우리는 항해지도의 특징인 좌표 그리드에 정확하게 도달합니다.




    쌀. 5. 세계의 해양 또는 메르카토르 지도. 이러한 지도에서는 ​​적도에서 멀리 떨어진 등고선의 치수가 크게 과장되어 있습니다. 예를 들어 그린란드와 호주 중 어느 것이 더 큽니까? (문자로 답변)


    메르카토르 카드에 대한 선원들의 선호가 이제 명확해졌습니다. 지정된 항구로 향하는 방향을 결정하기 위해 내비게이터는 경로의 끝점에 눈금자를 적용하고 자오선과 이루는 각도를 측정합니다. 항상 이 방향으로 넓은 바다를 유지하면서 네비게이터는 배를 정확하게 목표물에 데려다 줄 것입니다. 당신은 "loxodromia"- 가장 짧지도 않고 가장 경제적이지도 않지만 어떤 점에서는 선원에게 매우 편리한 방법이라는 것을 알 수 있습니다. 예를 들어 희망봉(Cape of Good Hope)에서 호주 남단까지 도달하려면(그림 1 참조) 항상 동일한 코스 S 87 °, 50 ". "를 유지해야 합니다. 그림에서 선박의 경로를 계속 변경하려면 S 42 °, 50" 코스에서 시작하여 N 53 °, 50" 코스로 끝납니다(이 경우 최단 경로는 불가능합니다. 남극의 얼음 벽에 대하여).

    "loxodrome"과 "orthodrome"을 따라 두 경로는 큰 원을 따라 경로가 바다 지도에 직선으로 표시될 때만 일치합니다: 적도를 따라 또는 자오선을 따라 이동할 때. 다른 모든 경우에는 이러한 경로가 다릅니다.