\documentclass{bschlangaul-aufgabe}
\bLadePakete{java,mathe,komplexitaetstheorie,pseudo}
\begin{document}
\bAufgabenMetadaten{
  Titel = {Aufgabe 4},
  Thematik = {Gutschein},
  Referenz = 66115-2020-H.T2-TA2-A4,
  RelativerPfad = Examen/66115/2020/09/Thema-2/Teilaufgabe-2/Aufgabe-4.tex,
  ZitatSchluessel = examen:66115:2020:09,
  BearbeitungsStand = mit Lösung,
  Korrektheit = unbekannt,
  Ueberprueft = {unbekannt},
  Stichwoerter = {Dynamische Programmierung},
  EinzelpruefungsNr = 66115,
  Jahr = 2020,
  Monat = 09,
  ThemaNr = 2,
  TeilaufgabeNr = 2,
  AufgabeNr = 4,
}

Das GUTSCHEIN-Problem ist gegeben durch eine Folge $w_1, \dots, w_n$ von
Warenwerten (wobei $w \in N_0$ für $i = 1, \dots, n$ ) und einem
Gutscheinbetrag $G \in \mathbb{N}_0$.
\index{Dynamische Programmierung}
\footcite{examen:66115:2020:09}

Da Gutscheine nicht in Bargeld ausgezahlt werden können, ist die Frage,
ob man eine Teilfolge der Waren findet, sodass man genau den Gutschein
ausnutzt. Formal ist dies die Frage, ob es eine Menge von Indizes $I$
mit $I \subseteq \{1, \dots, n \}$ gibt, sodass $\sum_{i \in I} w_i = G$

\begin{bExkurs}[Teilsummenproblem]
\bProblemSubsetSum
\end{bExkurs}

\begin{enumerate}

%%
% a)
%%

\item Sei $w_1 = 10, w_2 = 30, w_3 = 40, w_4 = 20, w_5 = 15$ eine Folge
von Warenwerten.

\begin{enumerate}

%%
% (ii)
%%

\item Geben Sie einen Gutscheinbetrag $40 < G < 115$ an, sodass die
GUT\-SCHEIN-Instanz eine Lösung hat. Geben Sie auch die lösende Menge $I
\subseteq \{ 1, 2, 3, 4, 5 \}$ von Indizes an.

\begin{bAntwort}
$50$

$I = \{ 1, 3 \}$
\end{bAntwort}

%%
% (ii)
%%

\item Geben Sie einen Gutscheinbetrag $G$ mit $40 < G < 115$ an, sodass
die GUTSCHEIN-Instanz keine Lösung hat.

\begin{bAntwort}
$51$
\end{bAntwort}

\end{enumerate}

%%
% b)
%%

\item Sei \emph{table} eine $(n \times (G + 1))$-Tabelle mit Einträgen
$\text{table}[i,k]$, für $1 \leq i \leq n$ und $0 \leq k \leq G$, sodass

\begin{equation*}
\text{table}[i,k] =
\begin{cases}
\textbf{true} &
\text{falls es } I \subseteq \{1, \dots, n \} \text{ mit }
\sum_{i \in I} w_i = G \text{ gibt}\\

\textbf{false} & \text{sonst}
\end{cases}
\end{equation*}

Geben Sie einen Algorithmus in Pseudo-Code oder Java an, der die Tabelle
\emph{table} mit \emph{dynamischer Programmierung} in
Worst-Case-Laufzeit $\mathcal{O}(n \times G)$) erzeugt. Begründen Sie
die Korrektheit und die Laufzeit Ihres Algorithmus. Welcher Eintrag in
\emph{table} löst das GUTSCHEIN-Problem?

\begin{bAntwort}
\begin{algorithm}[H]
\newcommand{\meinkommentar}[1]{\texttt{\scriptsize #1}}
\SetCommentSty{meinkommentar}

table = boolean array $n + 1 \times (G +  1)$
\tcp*{Initialisiere ein boolsches Feld mit $n + 1$ Zeilen für jeden
  Warenwert und 0 für keinen Warenwert und mit
  $G + 1$ Spalten für alle Gutscheinbetrag bis $G$ und $0$ für keinen Gutscheinbetrag}

\bigskip

\For(\tcp*{Wenn der Gutscheinbetrag größer als $0$ ist und es keine
     Warenwerte gibt, \dh $n = 0$, kann der Gutschein nicht eingelöst
     werden.}){$k$ in $1 \dots G$}{
  $\text{table}[0][k] = \text{false}$
}

\bigskip

\For(\tcp*{Ist der Gutscheinbetrag $0$, dann kann er immer eingelöst werden.}){$i$ in $0 \dots n$}{
  $\text{table}[i][0] = \text{true}$
}

\For(\tcp*{Durchlaufe jede Zeile der Warenwerte}){$i$ in $1 \dots n$}{
  \For(\tcp*{Durchlaufe jede Spalte der Gutscheinbeträge in dieser Zeile}){$k$ in $1 \dots G$}{
    $\text{table}[i][k] = \text{table}[i - 1][k]$
    \tcp*[r]{Übernehme erstmals das Ergebnis der Zelle der vorhergehenden
             Zeile in der gleichen Spalte}

    \If(\tcp*{Wenn der aktuelle Gutscheinbetrag größer als der aktuelle
              Warenwert und die aktuelle Zelle noch nicht als wahr
              markiert ist}){$k \geq w_i$ und $\text{table}[i][k]$ noch nicht markiert}{
      $\text{table}[i][k] = \text{table}[i - 1][k - w_i]$
      \tcp*{übernimmt das Ergebnis des aktuellen Gutscheinbetrags
            minus des aktuellen Warenwerts};
    }
  }
}
\caption{Gutschein-Problem}
\end{algorithm}

\bJavaExamen{66115}{2020}{09}{Gutschein}

Die äußere for-Schleife läuft $n$ mal und die innere for-Schleife $G$ mal.

Der letzte Eintrag in der Tabelle, also der Wert in der Zelle
\bJavaCode{table[W.length][G]}, löst das Gutscheinproblem. Steht hier
\bJavaCode{true}, dann gibt es eine Teilfolge der Waren, die den
Gutscheinbetrag genau ausnutzt.

\end{bAntwort}
\begin{bAdditum}[Test-Klasse]

\bJavaTestDatei{examen/examen_66115/jahr_2020/herbst/GutscheinTest}

\begin{itemize}
\item \bJavaCode{gutscheinDP(3, new int[] { 1, 2, 3 }));}: wahr (w)

\begin{minted}{md}
[
  [w, f, f, f],
  [w, w, f, f],
  [w, w, w, w],
  [w, w, w, w]
]
\end{minted}

\item \bJavaCode{gutscheinDP(7, new int[] { 1, 2, 3 });}: falsch (f)

\begin{minted}{md}
[   0  1  2  3  4  5  6  7 G
 0 [w, f, f, f, f, f, f, f],
 1 [w, w, f, f, f, f, f, f],
 2 [w, w, w, w, f, f, f, f],
 3 [w, w, w, w, w, w, w, f]
 W
]
\end{minted}

\item \bJavaCode{gutscheinDP(10, new int[] { 10, 30, 40, 20, 15 });}: wahr (w)

\begin{minted}{md}
[    0  1  2  3  4  5  6  7  8  9  10 G
 0  [w, f, f, f, f, f, f, f, f, f, f],
 10 [w, f, f, f, f, f, f, f, f, f, w],
 30 [w, f, f, f, f, f, f, f, f, f, w],
 40 [w, f, f, f, f, f, f, f, f, f, w],
 20 [w, f, f, f, f, f, f, f, f, f, w],
 15 [w, f, f, f, f, f, f, f, f, f, w]
 W
]
\end{minted}
\end{itemize}

\end{bAdditum}
\end{enumerate}
\end{document}
