Misc. documentation changes

This commit is contained in:
arnekeller 2019-04-09 21:55:32 +02:00
parent 679433d16c
commit 2d29c2761c

View File

@ -65,14 +65,14 @@
\tableofcontents \tableofcontents
\section{Lösungsidee} \section{Lösungsidee}
Zunächst kann man feststellen, dass der letzte Abschnitt jeder Route zum Bus immer exakt gerade ist. In einer Kurve würde Lisa länger laufen, ohne am Ende auf der y-Achse weiter zu sein. Es gibt keinen, einen oder zwei Treffpunkte, bei denen Lisa (ohne zu warten) den Bus erwischt: Zunächst kann man feststellen, dass jeder Abschnitt einer Route immer exakt gerade ist. In einer Kurve würde Lisa länger laufen, ohne am Ende weiter zu kommen. Wenn Lisa am Ende der Route zum Bus läuft, gibt es keinen, einen oder zwei Treffpunkte, bei denen Lisa (ohne zu warten) den Bus erwischt:
\begin{figure}[H] \begin{figure}[H]
\centering \centering
\begin{subfigure}{.33\textwidth} \begin{subfigure}{.33\textwidth}
\centering \centering
\begin{tikzpicture} \begin{tikzpicture}
\tkzInit[xmax=3.5,ymax=7.5] \tkzInit[xmax=3.5,ymax=7]
\tkzAxeXY \tkzAxeXY
\tkzGrid \tkzGrid
\tkzDefPoint(0,0){B} \tkzDefPoint(0,0){B}
@ -92,7 +92,7 @@ Zunächst kann man feststellen, dass der letzte Abschnitt jeder Route zum Bus im
\begin{subfigure}{.33\textwidth} \begin{subfigure}{.33\textwidth}
\centering \centering
\begin{tikzpicture} \begin{tikzpicture}
\tkzInit[xmax=3.5,ymax=7.5] \tkzInit[xmax=3.5,ymax=7]
\tkzAxeXY \tkzAxeXY
\tkzGrid \tkzGrid
\tkzDefPoint(0,0){B} \tkzDefPoint(0,0){B}
@ -111,7 +111,7 @@ Zunächst kann man feststellen, dass der letzte Abschnitt jeder Route zum Bus im
\begin{subfigure}{.33\textwidth} \begin{subfigure}{.33\textwidth}
\centering \centering
\begin{tikzpicture} \begin{tikzpicture}
\tkzInit[xmax=3.5,ymax=7.5] \tkzInit[xmax=3.5,ymax=7]
\tkzAxeXY \tkzAxeXY
\tkzGrid \tkzGrid
\tkzDefPoint(0,0){B} \tkzDefPoint(0,0){B}
@ -136,15 +136,15 @@ Zunächst kann man feststellen, dass der letzte Abschnitt jeder Route zum Bus im
d^2 &= x_{L}^2 + (y_{L}-y_{M})^2 \\ d^2 &= x_{L}^2 + (y_{L}-y_{M})^2 \\
&= x_{L}^2 + (y_{L}-y_{B}-2d)^2 &&\text{($y_{M} = y_{B} + 2d$)} \\ &= x_{L}^2 + (y_{L}-y_{B}-2d)^2 &&\text{($y_{M} = y_{B} + 2d$)} \\
&= x_{L}^2 + y_{L}^2 + y_{B}^2 + 4d^2 - 2y_{B}y_{L} - 4dy_{L} + 4dy_{B} \\ &= x_{L}^2 + y_{L}^2 + y_{B}^2 + 4d^2 - 2y_{B}y_{L} - 4dy_{L} + 4dy_{B} \\
-3d^2 + 4\cdot(y_{L}-y_{B})\cdot{}d &= x_{L}^2 + y_{L}^2 + y_{B}^2 - 2y_{B}y_{L} \\ 0 &= x_{L}^2 + y_{L}^2 + y_{B}^2 + 3d^2 - 2y_{B}y_{L} - 4dy_{L} + 4dy_{B} \\
d &= \frac{-b\pm\sqrt{b^2 + 12\cdot{}(-x_{L}^2 - y_{L}^2 - y_{B}^2 + 2y_{B}y_{L})}}{-6} &&\text{($b = 4\cdot(y_{L}-y_{B})$)} d &= \frac{-b\pm\sqrt{b^2 - 12\cdot{}(x_{L}^2 + y_{L}^2 + y_{B}^2 - 2y_{B}y_{L})}}{6} &&\text{($b = 4\cdot(y_{B}-y_{L})$)}
\end{align*} \end{align*}
Für diese Gleichung gibt es maximal zwei nicht-negative Lösungen.\qedhere Für diese Gleichung gibt es maximal zwei nicht-negative Lösungen.\qedhere
\end{proof} \end{proof}
Um den letzten Zeitpunkt, bei dem sie den Bus gerade noch erwischt, zu bestimmen, kann man die Wurzel in der letzen Gleichung gleich Null setzen. Wenn man nach $y_{B}$ auflöst, erhält man die Position des Busses, bei dessen Durchquerung Lisa anfangen sollte zu laufen. So kann man für jeden Startpunkt berechnen, wann Lisa spätestens von dort loslaufen müsste. Um den letzten Zeitpunkt, bei dem sie den Bus gerade noch erwischt, zu bestimmen, kann man die Wurzel in der letzen Gleichung gleich Null setzen. Wenn man nach $y_{B}$ auflöst, erhält man die Position des Busses, bei dessen Durchquerung Lisa anfangen sollte zu laufen. So kann man für jeden Startpunkt berechnen, wann Lisa spätestens von dort loslaufen müsste.
Außerdem wird Lisa auf einer optimalen Route vor dem letzten Abschnitt immer von einer Polygonecke zur nächsten gehen. Andernfalls würde sie in Kurven um jene Ecken wertvolle Zeit verschwenden. Der letzte Abschnitt ihrer Route trifft die y-Achse immer in einem 60\degree-Winkel (siehe Abb. \ref{fig:winkel}). Dieser Winkel ist vom Verhältnis der Geschwindigkeiten von Lisa und dem Bus abhängig: $cos(60\degree) = \frac{15}{30}$. Der letzte Abschnitt ihrer Route trifft die y-Achse immer in einem 60\degree-Winkel (siehe Abb. \ref{fig:winkel}). Dieser Winkel ist vom Verhältnis der Geschwindigkeiten von Lisa und dem Bus abhängig: $cos(60\degree) = \frac{15}{30}$.
\begin{figure}[H] \begin{figure}[H]
\centering \centering
@ -226,20 +226,20 @@ Das Programm liest die Problemstellung von der Standardeingabe ein. Die grafisch
Das vorgegebene Eingabeformat ist mühsam zu schreiben. Daher kann das Programm auch SVG-Dateien einlesen. Punkte werden als Startpunkte interpretiert, sonstige Pfade sind Hindernisse. Das vorgegebene Eingabeformat ist mühsam zu schreiben. Daher kann das Programm auch SVG-Dateien einlesen. Punkte werden als Startpunkte interpretiert, sonstige Pfade sind Hindernisse.
\section{Umsetzung} \section{Umsetzung}
Das Programm benutzt den Dijkstra-Algorithmus, um die beste Route für Lisa zu finden. Lisas Haus und die Ecken aller Polygone kann man sich als Graph vorstellen. Die Kanten des Graphen haben ein Gewicht, das der Zeit entspricht, die Lisa früher aufstehen müsste, wenn sie zu einer bestimmten Ecke geht, statt direkt zum Bus zu gehen. Um die Route abzuschließen, probiert das Programm danach immer, einen optimalen Weg zur y-Achse zu finden (dieser trifft sie im 60\degree-Winkel, wie oben beschrieben). Die Route, bei dem Lisa sich am meisten Zeit lassen kann, wird gespeichert. Das Programm benutzt den Dijkstra-Algorithmus, um die beste Route für Lisa zu finden. Lisas Haus und die Ecken aller Polygone kann als Graph darstellen. Die Kanten des Graphen haben ein Gewicht, das der Zeit entspricht, die Lisa früher aufstehen müsste, wenn sie zu einem bestimmten Punkt geht, statt direkt zum Bus zu gehen. Die Distanz zwischen zwei Punkten wäre definitv eine falsche Gewichtung, weil Lisa die y-Achse in einem bestimmten Winkel treffen sollte. Der kürzeste Weg würde höchstwahrscheinlich relativ direkt zur y-Achse führen, was nicht optimal ist. Um die Route abzuschließen, probiert das Programm danach immer, auf direktem Weg die y-Achse zu erreichen. Die Route, bei dem Lisa sich am meisten Zeit lassen kann, wird gespeichert.
Der Weg von Lisa und dem Bus wird animiert ausgegeben. Zusätzlich zu den unbedingt benötigten Ausgaben wie z.B. der Start- und Zielzeit gibt das Programm auch noch die theoretisch (ohne Hindernisse) beste Startzeit und während der Suche gefundene Verbesserungen aus. Der Weg von Lisa und dem Bus wird animiert ausgegeben. Zusätzlich zu den unbedingt benötigten Ausgaben wie z.B. der Start- und Zielzeit gibt das Programm auch noch die theoretisch (ohne Hindernisse) beste Startzeit aus. Nützlich sind auch die Debug-Ausgaben, die Statistiken zur Eingabedatei und der Performanz (Zeit/Iteration, Gesamtzeit) enthalten.
\subsection{Laufzeitanalyse} \subsection{Laufzeitanalyse}
Da programmintern der Dijkstra-Algorithmus verwendet wird, entspricht die Laufzeit in etwa diesem. Somit ist die Zeitkomplexität ca. $O(n^2)$, wobei $n$ die Anzahl der Ecken aller Polygone ist. Effektiv können allerdings in jedem Schritt nur eine kleine Anzahl anderer Ecken erreicht werden, was den Algorithmus beschleunigt. Da programmintern der Dijkstra-Algorithmus verwendet wird, entspricht die Laufzeit in etwa diesem. Somit ist die Zeitkomplexität ca. $O(n^2)$, wobei $n$ die Anzahl der Ecken aller Polygone ist. Effektiv können allerdings in jedem Schritt nur eine kleine Anzahl anderer Ecken erreicht werden, was den Algorithmus beschleunigt.
\subsection{Optimierungen} \subsection{Optimierungen}
Wie bereits in der Laufzeitanalyse kurz angesprochen, benutzt das Programm bestimmte Heuristiken, um die Suche zu beschleunigen. Eine davon ist die maximal mögliche Wartezeit für eine bestimmte Route. Dafür berechnet das Programm die höchstmögliche Position des Busses, was proportional zur gesuchten Größe ist. Das Programm benutzt bestimmte Heuristiken, um die Suche zu beschleunigen. Eine davon ist die maximal mögliche Wartezeit für eine bestimmte Route. Dafür berechnet das Programm die höchstmögliche Position des Busses, was proportional zur gesuchten Größe ist.
Um zu überprüfen, ob ein Routenabschnitt die Hindernisse schneidet, wird unter anderem ein R*-Baum benutzt. r ca. 40 Polygonen ist diese Methode ca. 5-6x schneller als alle Polygone zu überprüfen. Die Geschwindigkeitsgewinne werden größer, je mehr Polygone vorhanden sind. Zudem wird das Ergebnis in einer Hashtabelle gespeichert, was die insgesamte Performanz ca. 6-10x steigert. Um zu überprüfen, ob ein Routenabschnitt die Hindernisse schneidet, wird unter anderem ein R*-Baum benutzt. Ein R*-Baum funktioniert ähnlich wie ein Binärbaum, aber mit geometrischen Objekten. Für jedes Hindernis muss die Rechteckbox bestimmt werden, in die das Polygon genau passt. Aufgebaut wird der Baum dann aus diesen minimal umgebenden Rechtecken, wobei in jedem Indexknoten generell mehrere Unterknoten enthalten sind. Im Indexknoten ist auch das gemeinsame umgebende Rechteck gespeichert. So kann man dann für eine beliebige geometrische Figur (z. B. auch eine Linie) alle Polygone finden, die diese schneiden. Für ca. 40 Polygonen ist diese Methode ca. 5-6x schneller als alle Polygone zu überprüfen. Die Geschwindigkeitsgewinne werden größer, je mehr Polygone vorhanden sind. Zudem wird das Ergebnis in einer Hashtabelle gespeichert, was die insgesamte Performanz ca. 6-10x steigert.
\section{Beispiele} \section{Beispiele}
Alle Beispiele sind im Maßstab 1:70m. Für die folgenden fünf Beispiele benötigt das Programm höchstens 10 ms Rechenzeit. Alle Beispiele sind im Maßstab 1:70m. Für die folgenden fünf Beispiele benötigt das Programm höchstens 1 ms Rechenzeit.
\lstinputlisting[caption=Lösung für lisarennt1.txt,frame=single,breaklines=true]{run1.txt} \lstinputlisting[caption=Lösung für lisarennt1.txt,frame=single,breaklines=true]{run1.txt}
\begin{figure}[H] \begin{figure}[H]
\centering \centering
@ -276,49 +276,57 @@ Alle Beispiele sind im Maßstab 1:70m. Für die folgenden fünf Beispiele benöt
\label{fig:bsp5} \label{fig:bsp5}
\end{figure} \end{figure}
\subsection{Eigene Beispiele} \subsection{Eigene Beispiele}
Für diese benötigt das Programm höchstens 250 ms Rechenzeit. \lstinputlisting[caption=Lösung für Abb. \ref{fig:ebsp2} (5 ms Rechenzeit),frame=single,breaklines=true]{runwelt3.txt}
\lstinputlisting[caption=Lösung für Abb. \ref{fig:ebsp2},frame=single,breaklines=true]{runwelt3.txt}
\begin{figure}[H] \begin{figure}[H]
\centering \centering
\input{welt3.tkz} \input{welt3.tkz}
\caption{Heuristikfalle} \caption{Heuristikfalle}
\label{fig:ebsp2} \label{fig:ebsp2}
\end{figure} \end{figure}
\lstinputlisting[caption=Lösung für Abb. \ref{fig:ebsp3},frame=single,breaklines=true]{runwelt4.txt} \lstinputlisting[caption=Lösung für Abb. \ref{fig:ebsp3} (30 ms Rechenzeit),frame=single,breaklines=true]{runwelt4.txt}
\begin{figure}[H] \begin{figure}[H]
\centering \centering
\input{welt4.tkz} \input{welt4.tkz}
\caption{Angriff der Dreiecksgrundstücke (aus Aufgabe 2 entflohen)} \caption{Angriff der Dreiecksgrundstücke (aus Aufgabe 2 entflohen)}
\label{fig:ebsp3} \label{fig:ebsp3}
\end{figure} \end{figure}
\lstinputlisting[caption=Lösung für Abb. \ref{fig:ebsp4},frame=single,breaklines=true]{runwelt7b.txt} \lstinputlisting[caption=Lösung für Abb. \ref{fig:ebsp4} (250 ms Rechenzeit),frame=single,breaklines=true]{runwelt7b.txt}
\begin{figure}[H] \begin{figure}[H]
\centering \centering
\input{welt7b.tkz} \input{welt7b.tkz}
\caption{Text} \caption{Text}
\label{fig:ebsp4} \label{fig:ebsp4}
\end{figure} \end{figure}
\lstinputlisting[caption=Lösung für Abb. \ref{fig:ebsp5},frame=single,breaklines=true]{runwelt5.txt} \lstinputlisting[caption=Lösung für Abb. \ref{fig:ebsp5} (4 ms Rechenzeit),frame=single,breaklines=true]{runwelt5.txt}
\begin{figure}[H] \begin{figure}[H]
\centering \centering
\input{welt5.tkz} \input{welt5.tkz}
\caption{Mauern} \caption{Mauern}
\label{fig:ebsp5} \label{fig:ebsp5}
\end{figure} \end{figure}
\lstinputlisting[caption=Lösung für Abb. \ref{fig:ebsp6},frame=single,breaklines=true]{runwelt6.txt} \lstinputlisting[caption=Lösung für Abb. \ref{fig:ebsp6} (3 ms Rechenzeit),frame=single,breaklines=true]{runwelt6.txt}
\begin{figure}[H] \begin{figure}[H]
\centering \centering
\input{welt6.tkz} \input{welt6.tkz}
\caption{Oktagone} \caption{Oktagone}
\label{fig:ebsp6} \label{fig:ebsp6}
\end{figure} \end{figure}
\lstinputlisting[caption=Lösung für Abb. \ref{fig:ebsp7},frame=single,breaklines=true]{runwelt8.txt} \lstinputlisting[caption=Lösung für Abb. \ref{fig:ebsp7} (25 ms Rechenzeit),frame=single,breaklines=true]{runwelt8.txt}
\begin{figure}[H] \begin{figure}[H]
\centering \centering
\input{welt8.tkz} \input{welt8.tkz}
\caption{Höhle} \caption{Höhle}
\label{fig:ebsp7} \label{fig:ebsp7}
\end{figure} \end{figure}
\lstinputlisting[caption=Lösung für Abb. \ref{fig:ebsp8} (3 s Rechenzeit),frame=single,breaklines=true]{runwelt9.txt}
\begin{figure}[H]
\centering
\input{welt9.tkz}
\caption{Irrgarten}
\label{fig:ebsp8}
\end{figure}
\subsection{Performanzmessungen}
Die Routenberechnung für die Welt aus Abb. \ref{fig:ebsp3} benötigt ca. 30 ms (452 Ecken). Für vier dieser Welten, die in einem Quadrat angeordnet sind (1808 Ecken), benötigt das Programm ca. 900 ms. Die Laufzeit ist daher ungefähr proportional zu $n^{2.5}$, wobei $n$ die Anzahl der Ecken ist. Dies bestätigt auch eine weitere Messung mit einer nochmals so vergrößerten Welt: 7224 Ecken, 29000 ms.
\section{Quellcode (Hauptalgorithmus)} \section{Quellcode (Hauptalgorithmus)}
\lstinputlisting[frame=single,language=Rust,breaklines=true]{src/main.rs} \lstinputlisting[frame=single,language=Rust,breaklines=true]{src/main.rs}