uni/ad/AD-Gruppe_8_Koehler_Krabbe_...

335 lines
16 KiB
TeX

\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
\subsection{} %a
Der Algorithmus funktioniert nicht mehr. Dies wird anhand dieses Gegenbeispiels deutlich:
\begin{verbatim}
A = [0,1,4,8,10,13]
value = 1
low = 0
high = 5
// erster Schleifendurchlauf 0 < 5, daher Rumpf ausführen
mid = (0 + 5) / 2 = 2
// A[2] = 4 > value
high = 2 - 1 = 1
// zweiter Schleifendurchlauf 0 < 1, daher Rumpf ausführen
mid = (0 + 1) / 2 = 0
// A[0] = 0 < value
low = 0 + 1 = 1
// dritter Schleifendurchlauf 1 = 1, daher Rumpf nicht ausführen
return not_found
\end{verbatim}
Obwohl das Element vorhanden ist, wird zurückgegeben, dass es nicht vorhanden sei. Da es ein Gegenbeispiel gibt, funktioniert der Algorithmus nach der Änderung von \texttt{while (low <= high)} zu \texttt{while (low < high)} nicht mehr.
\subsection{} %b
\begin{verbatim}
BinarySearch(A[0..N-1], value) {
low = N - 1
high = 0
while (high <= low) {
// invariants: value > A[i] for all i < low
value < A[i] for all i > high
mid = (low + high) / 2
if (A[mid] > value)
high = mid + 1
else if (A[mid] < value)
low = mid - 1
else
return mid
}
return not_found
}
\end{verbatim}
\subsection{} %c
\textbf{Formaler Beweis:} Wir müssen beweisen, dass die while-Schleife endet. Angenommen wir befinden uns in Iteration $i$ der while-Schleife.
\begin{itemize}
\item Zu Beginn der while-Schleife haben wir \texttt{high $\leq$ low} (andernfalls hätten wir die while-Schleife nicht betreten).
\item Nach dem Ausdruck \texttt{mid = (low + high) / 2} gilt \texttt{high $\leq$ mid $\leq$ low}.
\item Entweder die Schleife wird durch die Rückgabe von \texttt{mid} beendet, womit wir fertig wären.
\item Oder sie befindet sich in einer der ersten beiden Fälle des if-Statements. Entweder high wird um mindestens eins erhöht oder low wird um mindestens eins verkleinert, wodurch sich in jedem Schleifendurchlauf die Differenz von \texttt{low - high} um mindestens eins verringert.
\item Damit gilt \texttt{low - high < 0} nach maximal $n$ Iterationen der while-Schleife und die Schleife terminiert.
\end{itemize}
\subsection{} %d
\textbf{Beweis der Korrektheit:}
Offensichtlich gibt der Algorithmus ein korrektes Ergebnis zurück, wenn \texttt{mid} zurückgegeben wird, da dann \texttt{A[mid] $=$ value} gilt.
Zu zeigen: Wenn der Algorithmus \texttt{not\_found} zurückgibt, dann kommt \texttt{value} tatsächlich nicht in dem Array vor.
Wir werden dies nun durch die Gegenposition beweisen: Wir müssen zeigen, dass wenn \texttt{value} im Array vorkommt, der Algorithmus \texttt{mid} zurückgibt.
\textbf{Erster Schritt:} Es ist einfach zu sehen, dass die folgenden Invarianten immer gelten:
\begin{itemize}
\item \texttt{value > A[i] for all i < low (strict inequality!)}
\item \texttt{value < A[i] for all i > high (strict inequality!)}
\end{itemize}
\textbf{Zweiter Schritt:} Annahme, dass \texttt{value} im Array vorkommt.
\begin{itemize}
\item Bereits bekannt: Invarianten sind wahr. Das bedeutet zu keinem Zeitpunkt im Algorithmus kann sich das Element, das wir suchen, links von \texttt{high} oder rechts von \texttt{low} befinden.
\item Der einzige Weg, wie wir theoretisch das gesuchte Element "`verpassen"' könnten, wäre, dass \texttt{high = mid + 1} oder \texttt{low = mid - 1} zu der Situation führen, dass \texttt{high > low} gilt bevor wir das gesuchte Element gefunden haben (weil wir dann die Schleife verlassen).
\begin{itemize}
\item Durch die Konstruktion des Algorithmus haben wir immer \texttt{high $\leq$ mid $\leq$ low} nachdem \texttt{mid = (low + high) / 2} ausgeführt wurde.
\item Solange \texttt{low $\geq$ high + 2} gilt, haben wir immer \texttt{high < mid < low}.
In dieser Situation, \texttt{mid - 1 $\geq$ high} und \texttt{mid + 1 $\leq$ low}, haben wir immer noch \texttt{high $\leq$ low} nachdem entweder \texttt{high = mid + 1} oder \texttt{low = mid - 1} ausgeführt wurden, sodass die while-Schleife ein weiteres Mal betreten wird.
Es gibt zwei kritische Fälle, in denen wir die Schleife verlassen könnten:
\begin{itemize}
\item \texttt{low = high}. Aber dann gilt auch \texttt{mid = high}. Nach der Annahme, dass \texttt{value} im Array ist, muss \texttt{A[high] = value} gelten. Durch die Rückgabe von \texttt{mid} wird demnach genau der richtige Index zurückgegeben.
\item \texttt{low = high + 1}. In diesem Fall gilt \texttt{mid = high}. Nun gilt entweder \texttt{A[high] = A[mid] = value}, wodurch durch Rückgabe von \texttt{mid} das richtige Ergebnis zurückgegeben würde, oder es gilt \texttt{A[high] = A[mid] > value}, wodurch \texttt{high} um eins erhöht würde, was beim nächsten Schleifendurchlauf im Fall \texttt{low = high} enden würde. In dem Fall wird das korrekte Ergebnis zurückgegeben, wie bereits gezeigt wurde.
\end{itemize}
\end{itemize}
\item Dies zeigt, dass wenn \texttt{value} im Array vorhanden ist, der Algorithmus immer damit endet \texttt{mid} zurückzugeben.
\end{itemize}
\section{} %2
\subsection{} %a
\subsubsection{} %i
In einem Graph ohne Kanten kann jeder Knoten gleich gefärbt sein. Dies gilt, weil die Bedingung $c_{k}(i= \neq c_{k}(j)$ nur gilt, wenn $i$ und $j$ mit einer Kante verbunden sind, was in solch einem Graphen nicht gegeben ist. Daher ist hier nichts zu zeigen.
\subsubsection{} %ii
Wenn ein Graph k-färbbar ist, dann kann man auch eine weitere Farbe in die Abbildung $c_{k}$ hinzunehmen ohne sie zu benutzen. Dies gilt da $c_{k}$ nicht surjektiv sein muss.
\subsubsection{} %iii
Man nehme einen k-färbbaren Graphen. Nun kann man solange weitere Farben hinzufügen, bis n Farben in der Abbildung vorkommen. Diese müssen jedoch nicht benutzt werden. Daher ist jeder Graph n-färbbar.
\subsection{} %b
\subsubsection{} %i
Wenn ein Graph 2-färbbar ist, dann gibt es keine Zyklen ungerader Länge. Bei einem Zyklus gerader Länge kann jeder zweiter Knoten die gleiche Farbe haben, ohne mit einem Knoten verbunden zu sein, der die gleiche Farbe hat.
Alle Knoten mit einer Farbe kann man als eine Untermenge einer Abbildung eines bipartiten Graphen verstehen.
\subsubsection{} %ii
\begin{verbatim}
IST_2FAERBUNG(G) {
kanten = E(G)
valid = true
farben = new Set()
foreach kante in kanten {
knoten1 = kante.knoten1
knoten2 = kante.knoten2
farben.add(knoten1.farbe)
farben.add(knoten2.farbe)
if (knoten1.farbe == knoten2.farbe) {
valid = false
break
}
}
return (valid && (farben.getAnzahl() == 2))
}
\end{verbatim}
\subsubsection{} %iii
Es gibt 2 verschiedene 2-Färbungen, sofern man unterschiedliche Farben nicht als Unterschied ansieht. Pro 2 Farben gibt es genau 2 verschiedene Färbungen.
\subsection{} %c
Bei einer beliebigen Landkarte werden mindestens vier Farben benötigt, damit direkt benachbarte Länder stets unterschiedliche Farben haben.
\subsubsection{} %i
\begin{tikzpicture}
\node (altona) {A};
\node (eimsbuettel) [above right=of altona] {E};
\node (nord) [right=of eimsbuettel] {N};
\node (wandsbek) [right=of nord] {W};
\node (mitte) [below=of eimsbuettel] {M};
\node (harburg) [below left=of mitte] {H};
\node (bergedorf) [below right=of mitte] {B};
\path[every node/.style={font=\scriptsize}]
(altona) edge (mitte)
(altona) edge (eimsbuettel)
(mitte) edge (harburg)
(mitte) edge (bergedorf)
(mitte) edge (eimsbuettel)
(mitte) edge (nord)
(mitte) edge (wandsbek)
(eimsbuettel) edge (nord)
(nord) edge (wandsbek);
\end{tikzpicture}
\subsubsection{} %ii
\begin{alignat*}{2}
c_{k}(A) &=& gelb \\
c_{k}(E) &=& rot \\
c_{k}(M) &=& blau \\
c_{k}(H) &=& rot \\
c_{k}(B) &=& rot \\
c_{k}(N) &=& gelb \\
c_{k}(W) &=& rot
\end{alignat*}
\subsubsection{} %iii
Die Aussage, dass vier Farben minimal sind, besagt nur, dass man es bei einer beliebigen Landkarte schafft diese mit maximal vier Farben zu färben. Es gibt die Obergrenze der nötigen Farben an. Die Regel besagt hingegen nicht, dass immer mindestens vier Farben benötigt werden. Bei einer Landkarte mit nur zwei aneinandergrenzenden Ländern reichen auch zwei Farben. Bei einer Karte mit nur einer zusammenhängenden Fläche ohne angrenzende Flächen reicht sogar eine Farbe.
\subsubsection{} %iv
\begin{tikzpicture}
\node (sh) {SH};
\node (hh) [below right=of sh] {HH};
\node (meck) [right=of hh] {MP};
\node (bremen) [below left=of hh] {B};
\node (nieder) [below=of hh] {N};
\path[every node/.style={font=\scriptsize}]
(sh) edge (hh)
(sh) edge (meck)
(hh) edge (nieder)
(bremen) edge (nieder)
(sh) edge (nieder)
(bremen) edge (sh)
(bremen) edge (hh);
\end{tikzpicture}
In dieser konstruierten Karte (dargestellt als Graph), müssen mindestens vier Farben verwendet werden.
\section{} %3
\subsection{} %a
\[
G_{1}: 1, 3, 4, 5, 2, 8, 6, 7
\]
\[
G_{2}: 1, 3, 5, 6, 4, 7, 2
\]
\subsection{} %b
\[
G_{1}: 4, 3, 7, 6, 8, 2, 5, 1
\]
\[
G_{2}: 4, 6, 5, 3, 2, 7, 1
\]
\subsection{} %c
\[
G_{1}: 1, 3, 5, 4, 2, 7, 8, 6
\]
\[
G_{2}: 1, 3, 4, 7, 5, 2, 6
\]
\subsection{} %d
Für $G_1$ existiert keine topologische Sortierung, da es sich nicht um einen DAG (Directed acyclic graph) handelt. Dies erkennt man daran, dass beispielsweise ein Zyklus von 1 über 5 über 2 zurück zur 1 existiert. $\square$
Für $G_2$ existieren topologische Sortierungen, z.B.:
\[
1, 3, 5, 6, 4, 7, 2
\]
\subsection{} %e
Wie bereits etabliert, existieren für $G_1$ keine mit ihm konsistenten topologischen Sortierungen. Für $G_2$ allerdings existieren mehrere:
Nach Proposition 5 (Uniqueness of topological Sort) im Skript, Folie 163, ist eine topologische Sortierung nur eindeutig, wenn der dazugehörige Graph einen Hamilton-Kreis enthält. $G_2$ enthält keinen Hamilton-Kreis. Dies ist leicht zu erkennen: es gibt keinen Pfad in dem Graphen, der die Knoten $2$ \textit{und} $3$ besucht. Daher gibt es mehrere topologische Sortierungen.
Eine weitere wäre z.B.:
\[
1, 7, 2, 5, 6, 4, 3
\]
\subsection{} %f
starke Zusammenhangskomponenten von $G_{1}:$
\begin{alignat*}{2}
comp1:&&\; 1, 2, 5, 6, 7, 8 \\
comp2:&&\; 3 \\
comp3:&&\; 4
\end{alignat*}
starke Zusammenhangskomponenten von $G_{2}:$
\begin{alignat*}{1}
comp1: 1 \\
comp2: 2 \\
comp3: 3 \\
comp4: 4 \\
comp5: 5 \\
comp6: 6 \\
comp7: 7
\end{alignat*}
\section{} %4
\subsection{} %a
% Senken finden (alle Senken infiltrieren, dadurch werden alle Module eliminiert)
% Algorithmus aus Vorlesung benutzen
Es müssen alle Module (oder Knoten) ohne eingehende Kanten eliminiert (bzw. markiert) werden, da diese andernfalls nie erreicht werden können. Zu allen anderen Knoten muss es gerichtete Pfade von einem dieser Knoten geben. Ausnahmen können starke Zusammenhangskomponenten bilden. In jeder starken Zusammenhangskomponente wird daher ebenfalls ein Knoten eliminiert.
\newpage
\begin{verbatim}
function eliminiereMCP() {
int zaehler = 0
list infiltrierteKnoten
// füge alle Knoten ohne Vorgänger hinzu:
for-all v in Knotenmenge:
if v.eingehendeKanten == 0:
infiltriere(v)
infiltrierteKnoten.add(v)
end if
end for-all
// füge einen Knoten aus jeder
// starken Zusammenhangskomponente hinzu:
list starkZusammenhaengend = findeStarkeZusammenhangskomponenten()
for-all elemente in starkZusammenhaengend:
for i = 0; i < elemente.length; i++
if infiltrierteKnoten.contains(elemente[i]):
zaehler++
end if
if zaehler == 0:
infiltriere(elemente[0])
infiltrierteKnoten.add(elemente[0])
end if
end for
end for-all
eliminiere(infiltrierteKnoten)
}
\end{verbatim}
\subsection{} %b
Wenn alle Senken infiltriert werden, werden dadurch alle Module eliminiert, da alle Module direkt oder indirekt mit mindestens einer Senke verbunden sind.
\subsection{} %c
Es müssen alle Senken infiltriert werden, da ansonsten einzelne Module nicht eliminiert werden könnten.
\section*{Zusatzaufgabe} %Zusatz
Beweis der Terminierung für beliebige natürliche Zahlen größer $0$.\\
Trivialer Fall: \\
Der Algorithmus terminiert für $n=1$. \\
Zweiter Fall: \\
Der Algorithmus terminiert für $2^{c} = n$. Dies gilt, da damit nach $c$ Rekursionsschritten immer $n=1$ gilt. \\
Dritter Fall: \\
Es ist zu zeigen, dass nach endlich vielen Rekursionsschritten \textsc{Coll} mit einer 2er-Potenz aufgerufen wird.
Dazu lohnt es sich die verbleibenden Zahlen bis 10 anzuschauen.
\begin{alignat*}{2}
3 \rightarrow 10 \rightarrow 5 \rightarrow 16 \\
5 \rightarrow 16 \\
6 \rightarrow 3 \\
7 \rightarrow 22 \rightarrow 11 \rightarrow 34 \rightarrow 17 \rightarrow 52 \rightarrow 26 \rightarrow 13 \rightarrow 40 \rightarrow 20 \rightarrow 10 \rightarrow 5 \rightarrow 16 \\
9 \rightarrow 28 \rightarrow 14 \rightarrow 7 \\
10 \rightarrow 5
\end{alignat*}
Was kann aus dieser Reihe geschlossen werden? Alle Zahlen, die aus dem Produkt einer 2er-Potenz und einer dieser Zahlen entstehen, lassen sich auf eine 2er-Potenz zurückführen. Auf diese Weise könnte man für die ersten $d$ natürlichen Zahlen zeigen, dass sie sich alle auf eine 2er-Potenz zurückführen lassen.
Aufgrund dieser Annahme steigt die Wahrscheinlichkeit bei einem Rekursionsaufruf mit $3n+1$ auf ein solches Vielfaches einer bereits auf eine 2er-Potenz zurückgeführte Zahl zu stoßen.
Da es jedoch unendlich viele Primzahlen gibt, wenngleich sich deren Abstand zueinander immer weiter erhöht, findet man immer Zahlen, die noch nicht auf eine 2er-Potenz zurückgeführt sind. Aufgrund dieser Tatsache kann es keine allgemeingültige Aussage für alle natürlichen Zahlen geben. Allerdings kann dieser Algorithmus selbst als Antwort verstanden werden. Für eine beliebig große Zahl, die nicht ein gerades Vielfaches einer bereits zurückgeführten Zahl ist, muss daher nur der Algorithmus ausgeführt werden bis ein solches Vielfaches erreicht wurde.
Nach endlich vielen Schritten wird dies praktisch der Fall sein, wenngleich die Anzahl dieser Schritte dramatisch zunehmen wird. Es ist jedoch nicht möglich dafür einen theoretischen Beweis zu finden, der ebenjene Tatsache darlegen kann.
\end{document}