\documentclass[10pt,a4paper,oneside,ngerman,numbers=noenddot]{scrartcl} \usepackage[T1]{fontenc} \usepackage[utf8]{inputenc} \usepackage[ngerman]{babel} \usepackage{amsmath} \usepackage{amsfonts} \usepackage{amssymb} \usepackage{bytefield} \usepackage{paralist} \usepackage{gauss} \usepackage{pgfplots} \usepackage{textcomp} \usepackage[locale=DE,exponent-product=\cdot,detect-all]{siunitx} \usepackage{tikz} \usepackage{algorithm} \usepackage{algorithmic} \usetikzlibrary{automata,matrix,fadings,calc,positioning,decorations.pathreplacing,arrows,decorations.markings} \usepackage{polynom} \polyset{style=C, div=:,vars=x} \pgfplotsset{compat=1.8} \pagenumbering{arabic} \def\thesection{\arabic{section})} \def\thesubsection{(\alph{subsection})} \def\thesubsubsection{(\roman{subsubsection})} \makeatletter \renewcommand*\env@matrix[1][*\c@MaxMatrixCols c]{% \hskip -\arraycolsep \let\@ifnextchar\new@ifnextchar \array{#1}} \makeatother \parskip 12pt plus 1pt minus 1pt \parindent 0pt \begin{document} \author{Reinhard Köhler (6425686), Tronje Krabbe (6435002), \\ Jim Martens (6420323)} \title{Hausaufgaben zum 4. Dezember} \subtitle{Gruppe 8} \maketitle \section{} %1 Dieser folgende Pseudocode beschreibt eine leichte Abänderung, die vorzeitig abbricht, wenn sich nach einem kompletten Durchlauf aller Kanten nichts geändert hat. Nach $m$ Durchläufen hat der Algorithmus alle kürzeste Pfade mit maximal $m$ Kanten entdeckt. In einem weiteren Durchlauf wird sich dann nichts mehr ändern, da keine neuen kürzesten Pfade mehr gefunden werden können, wodurch die geänderte Variante abbricht. Um die Abbruchbedingung zu erreichen muss $m$ nicht bekannt sein, da nach $m+1$ Durchläufen die Abbruchbedingung immer gegeben ist. \begin{verbatim} function BellmanFord(G,s) InitializeSingleSource(G,s) for i = 1, ... |V| - 1 changed = false for all edges (u,v) in E changedTmp = Relax(u,v) if (!changed) changed = changedTmp if (!changed) break for all edges (u,v) in E if v.dist > u.dist + w(u,v) return false return true \end{verbatim} \section{} %2 \begin{verbatim} function DAG-SP(G,s) sort vertices topologically InitializeSingleSource(G,s) for each u in V in topological sort order for each v in Adj(u) Relax(u,v) \end{verbatim} \section{} %3 Wir wissen, dass der Dijkstra-Algorithmus für rein positive Kantengewichte funktioniert. Es bleibt also nur zu zeigen, dass die kürzesten Wege zu den Knoten korrekt berechnet werden, die eine Kante von dem Startknoten entfernt sind. Ferner ist bekannt, dass Dijkstra zuerst den Knoten besucht, der am billigsten zu erreichen ist. Damit geht der Algorithmus die Kante mit dem kleinsten Gewicht zu erst (einschließlich negative Gewichte). Der somit erreichte Knoten kann also gar nicht billiger zu erreichen sein, da jeder andere Pfad dorthin aus mindestens zwei Kanten besteht, die zusammen bestenfalls das gleiche Gewicht haben wie die gegangene Kante. Dies ist so, da die erste Kante vom Startknoten zu einem anderen Knoten minimal so klein sein kann, wie die zuerst gegangene Kante, da andernfalls die zuerst gegangene Kante nicht das geringste Gewicht gehabt hätte. Die zweite Kante muss mindestens 0 als Gewicht haben, womit nur ein gleich großes oder größeres Gesamtgewicht entstehen kann, als durch die zuerst gegangene Kante verwendet wurde. \section{} %4 \subsection{} %a In einem Baum gibt es keine Zyklen. Daher gibt es genau einen direkten Weg (ohne Umwege mit mehrmaligem Besuchen eines Knotens) zu jedem Knoten von dem Wurzelknoten aus. Demnach müssen einfach vom Wurzelknoten aus alle Knoten besucht werden. Dabei wird ähnlich wie in der Breitensuche vorgegangen, indem zunächst alle Knoten, die direkt mit dem Wurzelknoten per Kante verbunden sind, besucht werden und anschließend alle Knoten, die zwei Kanten vom Wurzelknoten entfernt sind, etc. Dabei wird eine Variable zu Beginn auf 0 gesetzt und bei jedem Knoten wird geschaut, ob seine Entfernung zum Wurzelknoten größer ist als diese Variable. Wenn dem so ist, dann wird die Variable entsprechend angepasst. Nach einmaligem Besuchen jedes Knotens hat man damit die längste Entfernung eines Knotens von dem Wurzelknoten ermittelt. In Pseudocode sieht das dann so aus: \begin{verbatim} function berechneDurchmesser(G) longestPath = 0 current = G.root queue.enqueue(current.getChilds()) while (!empty(queue)) current = queue.dequeue() parent = current.parent distance = parent.getDistance() + w(parent,current) current.setDistance(distance) if (distance > longestPath) longestPath = distance childs = current.getChilds() if (!empty(childs)) queue.enqueue(current.getChilds()) \end{verbatim} \subsection{} %b \begin{verbatim} Diam(G) longestPath = 0 for each v1 in G.vertices for each v2 in G.vertices with v1 != v2 find shortest path P from v1 to v2 if P.length > longestPath longestPath = P.length return longestPath \end{verbatim} Die Laufzeit dieses Algorithmus beträgt $\mathcal{O}(|V|^3)$. \section{} %5 \subsection{} %a Man konstruiere aus der Währungsadjazenzmatrix einen vollständigen Graphen, in dem die Währungen durch Knoten repräsentiert sind und die Werte der Matrix als Kantengewichte verwendet werden. Anhand dieses Graphen kann geprüft werden, ob für einen Zyklus die multiplizierten Kantengewichte einen Wert ungleich 1 ergeben. In solch einem Fall würde es Währungsarbitrage geben. Gibt es keinen solchen Zyklus, dann gibt es keine Währungsarbitragen in der Adjazenzmatrix. \subsection{} %b Nein, da dafür negative Werte in der Adjazenzmatrix erforderlich wären. Diese würden bedeuten, dass man sein komplettes Geld bei einem Tausch verlöre und sogar Strafe zahlen müsste. \section{} %6 \begin{tikzpicture}[shorten >=1pt,node distance=1.1cm] \node[state] (s) {s}; \node[state] (a) [above right=1.5 and 1.0 of s] {A}; \node[state] (b) [below right=1.5 and 1.0 of s] {B}; \node[state] (d) [above right=1.0 and 1.0 of a] {D}; \node[state] (c) [right=of a] {C}; \node[state] (f) [below right=1.0 and 1.25 of a] {F}; \node[state] (e) [right=1.0 of c] {E}; \node[state] (g) [right=of f] {G}; \path[every node/.style={font=\scriptsize},->] (s) edge node [above] {30} (a) (s) edge node [below] {18} (b) (a) edge node [above] {21} (c) (a) edge node [above] {38} (d) (a) edge node [below] {22} (f) (c) edge node [right] {22} (f) (c) edge node [above] {20} (e) (f) edge node [above] {9} (g) (b) edge node [left] {30} (a); \end{tikzpicture} Da dies ein gerichteter Graph ohne Zyklen ist und auch keine negativen Kantengewichte vorkommen, kann der Dijkstra-Algorithmus angewendet werden. Da von 9 bis 17 Uhr Fahrer bezahlt werden müssen, kommen nur die Pfade in Betrachtung, die zu einer Senke führen. Senken sind D, E und G. Derjenige dieser Knoten welcher als erster vom Algorithmus gefunden wird (über den eindeutig bestimmbaren Weg), ist auch der kürzeste Pfad vom Startknoten aus, der die Bedingungen erfüllt. Es ergibt sich folgende Abfolge: \begin{verbatim} S = {s} d(s) = 0 while 1. U = {A, B} for all u in U -> u = A for all pre(u) in S that are predecessors of u -> pre(u) = s d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 0 + 30 for all u in U -> u = B for all pre(u) in S that are predecessors of u -> pre(u) = s d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 0 + 18 u* = B d(u*) = 18 S = {s, B} while 2. U = {A} for all u in U -> u = A for all pre(u) in S that are predecessors of u -> pre(u) = s d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 0 + 30 for all pre(u) in S that are predecessors of u -> pre(u) = B d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 18 + 30 u* = A d(u*) = 30 S = {S, B, A} while 3. U = {D, C, F} for all u in U -> u = D for all pre(u) in S that are predecessors of u -> pre(u) = A d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 30 + 38 for all u in U -> u = C for all pre(u) in S that are predecessors of u -> pre(u) = A d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 30 + 21 for all u in U -> u = F for all pre(u) in S that are predecessors of u -> pre(u) = A d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 30 + 22 u* = C d(u*) = 51 S = {s, B, A, C} while 4. U = {D, F, E} for all u in U -> u = D for all pre(u) in S that are predecessors of u -> pre(u) = A d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 30 + 38 for all u in U -> u = F for all pre(u) in S that are predecessors of u -> pre(u) = A d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 30 + 22 for all pre(u) in S that are predecessors of u -> pre(u) = C d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 51 + 22 for all u in U -> u = E for all pre(u) in S that are predecessors of u -> pre(u) = C d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 51 + 20 u* = F d(u*) = 52 S = {s, B, A, C, F} while 5. U = {D, E, G} for all u in U -> u = D for all pre(u) in S that are predecessors of u -> pre(u) = A d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 30 + 38 for all u in U -> u = E for all pre(u) in S that are predecessors of u -> pre(u) = C d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 51 + 20 for all u in U -> u = G for all pre(u) in S that are predecessors of u -> pre(u) = F d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 52 + 9 u* = G d(u*) = 61 S = {s, B, A, C, F, G} while 6. U = {D, E} for all u in U -> u = D for all pre(u) in S that are predecessors of u -> pre(u) = A d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 30 + 38 for all u in U -> u = E for all pre(u) in S that are predecessors of u -> pre(u) = C d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 51 + 22 u* = D d(u*) = 68 S = {s, B, A, C, F, G, D} while 7. U = {E} for all u in U -> u = E for all pre(u) in S that are predecessors of u -> pre(u) = C d'(u, pre(u)) = d(pre(u)) + w(pre(u), u) d'(u, pre(u)) = 51 + 20 u* = E d(u*) = 71 S = {s, B, A, C, F, G, D, E} \end{verbatim} Wie zu sehen ist wird die Senke G zuerst erreicht. Folgt man dem Weg zu G, so ergibt sich, dass der kürzeste Pfad von s über A und F nach G führt. Weniger Kosten als 61 sind daher nicht möglich. \end{document}