Corrections
This commit is contained in:
parent
3dd874a4fa
commit
3f31020076
46
luku05.tex
46
luku05.tex
|
@ -2,7 +2,7 @@
|
|||
|
||||
\key{Complete search}
|
||||
is a general method that can be used
|
||||
for solving almost any algorithm problem.
|
||||
to solve almost any algorithm problem.
|
||||
The idea is to generate all possible
|
||||
solutions to the problem using brute force,
|
||||
and then select the best solution or count the
|
||||
|
@ -30,7 +30,7 @@ or use bit operations of integers.
|
|||
|
||||
An elegant way to go through all subsets
|
||||
of a set is to use recursion.
|
||||
The following function \texttt{gen}
|
||||
The following function
|
||||
generates the subsets of the set
|
||||
$\{1,2,\ldots,n\}$.
|
||||
The function maintains a vector
|
||||
|
@ -128,8 +128,8 @@ which corresponds to an integer between $0 \ldots 2^n-1$.
|
|||
The ones in the bit sequence indicate
|
||||
which elements are included in the subset.
|
||||
|
||||
The usual convention is that element $k$
|
||||
is included in the subset if the $k$th last bit
|
||||
The usual convention is that the $k$th element
|
||||
is included in the subset exactly when the $k$th last bit
|
||||
in the sequence is one.
|
||||
For example, the bit representation of 25
|
||||
is 11001, that corresponds to the subset $\{1,4,5\}$.
|
||||
|
@ -143,8 +143,8 @@ for (int b = 0; b < (1<<n); b++) {
|
|||
}
|
||||
\end{lstlisting}
|
||||
|
||||
The following code shows how we can derive
|
||||
the elements in a subset from the bit sequence.
|
||||
The following code shows how we can find
|
||||
the elements of a subset that corresponds to a bit sequence.
|
||||
When processing each subset,
|
||||
the code builds a vector that contains the
|
||||
elements in the subset.
|
||||
|
@ -165,14 +165,14 @@ for (int b = 0; b < (1<<n); b++) {
|
|||
Next we will consider the problem of generating
|
||||
all permutations of a set of $n$ elements.
|
||||
Again, there are two approaches:
|
||||
we can either use recursion or go trough the
|
||||
we can either use recursion or go through the
|
||||
permutations iteratively.
|
||||
|
||||
\subsubsection{Method 1}
|
||||
|
||||
Like subsets, permutations can be generated
|
||||
using recursion.
|
||||
The following function \texttt{gen} goes
|
||||
The following function goes
|
||||
through the permutations of the set $\{1,2,\ldots,n\}$.
|
||||
The function builds a vector that contains
|
||||
the elements in the permutation,
|
||||
|
@ -180,7 +180,7 @@ and the search begins when the function is
|
|||
called without parameters.
|
||||
|
||||
\begin{lstlisting}
|
||||
void haku() {
|
||||
void gen() {
|
||||
if (v.size() == n) {
|
||||
// process permutation v
|
||||
} else {
|
||||
|
@ -188,7 +188,7 @@ void haku() {
|
|||
if (p[i]) continue;
|
||||
p[i] = 1;
|
||||
v.push_back(i);
|
||||
haku();
|
||||
gen();
|
||||
p[i] = 0;
|
||||
v.pop_back();
|
||||
}
|
||||
|
@ -275,8 +275,9 @@ any of the queens placed before.
|
|||
A solution has been found when all
|
||||
$n$ queens have been placed to the board.
|
||||
|
||||
For example, when $n=4$, the backtracking
|
||||
algorithm generates the following tree:
|
||||
For example, when $n=4$,
|
||||
some partial solutions generated by
|
||||
the backtracking algorithm are as follows:
|
||||
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=.55]
|
||||
|
@ -436,7 +437,7 @@ the $4 \times 4$ board are numbered as follows:
|
|||
\end{center}
|
||||
|
||||
The above backtracking
|
||||
algorithm shows that
|
||||
algorithm tells us that
|
||||
there are 92 ways to place 8
|
||||
queens to the $8 \times 8$ chessboard.
|
||||
When $n$ increases, the search quickly becomes slow,
|
||||
|
@ -453,7 +454,7 @@ on a modern computer
|
|||
We can often optimize backtracking
|
||||
by pruning the search tree.
|
||||
The idea is to add ''intelligence'' to the algorithm
|
||||
so that it will realize as soon as possible
|
||||
so that it will notice as soon as possible
|
||||
if a partial solution cannot be extended
|
||||
to a complete solution.
|
||||
Such optimizations can have a tremendous
|
||||
|
@ -484,7 +485,8 @@ One of the paths is as follows:
|
|||
\end{tikzpicture}
|
||||
\end{center}
|
||||
|
||||
Next we will concentrate on the $7 \times 7$ case.
|
||||
We will concentrate on the $7 \times 7$ case,
|
||||
because its level of difficulty is appropriate to our needs.
|
||||
We begin with a straightforward backtracking algorithm,
|
||||
and then optimize it step by step using observations
|
||||
how the search can be pruned.
|
||||
|
@ -509,7 +511,7 @@ recursive calls: 76 billions
|
|||
|
||||
\subsubsection{Optimization 1}
|
||||
|
||||
In any solution, we first move a step
|
||||
In any solution, we first move one step
|
||||
down or right.
|
||||
There are always two paths that
|
||||
are symmetric
|
||||
|
@ -551,7 +553,7 @@ For example, the following paths are symmetric:
|
|||
\end{center}
|
||||
|
||||
Hence, we can decide that we always first
|
||||
move down,
|
||||
move one step down,
|
||||
and finally multiply the number of the solutions by two.
|
||||
|
||||
\begin{itemize}
|
||||
|
@ -683,9 +685,9 @@ i.e., at the top of the search tree.
|
|||
|
||||
\key{Meet in the middle} is a technique
|
||||
where the search space is divided into
|
||||
two equally large parts.
|
||||
two parts of about equal size.
|
||||
A separate search is performed
|
||||
for each of the parts,
|
||||
for both of the parts,
|
||||
and finally the results of the searches are combined.
|
||||
|
||||
The technique can be used
|
||||
|
@ -727,8 +729,8 @@ to a list $S_A$.
|
|||
Correspondingly, the second search creates
|
||||
a list $S_B$ from $B$.
|
||||
After this, it suffices to check if it is possible
|
||||
to choose one number from $S_A$ and another
|
||||
number from $S_B$ so that their sum is $x$.
|
||||
to choose one element from $S_A$ and another
|
||||
element from $S_B$ so that their sum is $x$.
|
||||
This is possible exactly when there is a way to
|
||||
form the sum $x$ using the numbers in the original list.
|
||||
|
||||
|
@ -736,7 +738,7 @@ For example, suppose that the list is $[2,4,5,9]$ and $x=15$.
|
|||
First, we divide the list into $A=[2,4]$ and $B=[5,9]$.
|
||||
After this, we create lists
|
||||
$S_A=[0,2,4,6]$ and $S_B=[0,5,9,14]$.
|
||||
In this case, the sum $x=15$ is possible to form
|
||||
In this case, the sum $x=15$ is possible to form,
|
||||
because we can choose the number $6$ from $S_A$
|
||||
and the number $9$ from $S_B$,
|
||||
which corresponds to the solution $[2,4,9]$.
|
||||
|
|
30
luku06.tex
30
luku06.tex
|
@ -12,8 +12,8 @@ the final solution.
|
|||
For this reason, greedy algorithms
|
||||
are usually very efficient.
|
||||
|
||||
The difficulty in designing a greedy algorithm
|
||||
is to invent a greedy strategy
|
||||
The difficulty in designing greedy algorithms
|
||||
is to find a greedy strategy
|
||||
that always produces an optimal solution
|
||||
to the problem.
|
||||
The locally optimal choices in a greedy
|
||||
|
@ -32,7 +32,7 @@ $\{c_1,c_2,\ldots,c_k\}$,
|
|||
and each coin can be used as many times we want.
|
||||
What is the minimum number of coins needed?
|
||||
|
||||
For example, if the coins are euro coins (in cents)
|
||||
For example, if the coins are the euro coins (in cents)
|
||||
\[\{1,2,5,10,20,50,100,200\}\]
|
||||
and the sum of money is 520,
|
||||
we need at least four coins.
|
||||
|
@ -71,13 +71,13 @@ because we could replace
|
|||
coins $2+2+2$ by coins $5+1$ and
|
||||
coins $20+20+20$ by coins $50+10$.
|
||||
Moreover, an optimal solution cannot contain
|
||||
coins $2+2+1$ or $20+20+10$
|
||||
coins $2+2+1$ or $20+20+10$,
|
||||
because we could replace them by coins $5$ and $50$.
|
||||
|
||||
Using these observations,
|
||||
we can show for each coin $x$ that
|
||||
it is not possible to optimally construct
|
||||
sum $x$ or any larger sum by only using coins
|
||||
a sum $x$ or any larger sum by only using coins
|
||||
that are smaller than $x$.
|
||||
For example, if $x=100$, the largest optimal
|
||||
sum using the smaller coins is $50+20+20+5+2+2=99$.
|
||||
|
@ -113,10 +113,10 @@ correct answer.
|
|||
\section{Scheduling}
|
||||
|
||||
Many scheduling problems can be solved
|
||||
using a greedy strategy.
|
||||
using greedy algorithms.
|
||||
A classic problem is as follows:
|
||||
Given $n$ events with their starting and ending
|
||||
times, we should plan a schedule
|
||||
times, our goal is to plan a schedule
|
||||
that includes as many events as possible.
|
||||
It is not possible to select an event partially.
|
||||
For example, consider the following events:
|
||||
|
@ -172,7 +172,7 @@ selects the following events:
|
|||
\end{tikzpicture}
|
||||
\end{center}
|
||||
|
||||
However, select short events is not always
|
||||
However, selecting short events is not always
|
||||
a correct strategy, but the algorithm fails,
|
||||
for example, in the following case:
|
||||
\begin{center}
|
||||
|
@ -269,9 +269,9 @@ and the greedy algorithm is correct.
|
|||
\section{Tasks and deadlines}
|
||||
|
||||
Let us now consider a problem where
|
||||
we are given $n$ tasks with durations and deadlines,
|
||||
we are given $n$ tasks with durations and deadlines
|
||||
and our task is to choose an order to perform the tasks.
|
||||
For each task, we get $d-x$ points
|
||||
For each task, we earn $d-x$ points
|
||||
where $d$ is the task's deadline
|
||||
and $x$ is the moment when we finished the task.
|
||||
What is the largest possible total score
|
||||
|
@ -367,7 +367,7 @@ Here $a>b$, so we should swap the tasks:
|
|||
\end{scope}
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
Now $X$ gives $b$ points less and $Y$ gives $a$ points more,
|
||||
Now $X$ gives $b$ points fewer and $Y$ gives $a$ points more,
|
||||
so the total score increases by $a-b > 0$.
|
||||
In an optimal solution,
|
||||
for any two consecutive tasks,
|
||||
|
@ -470,7 +470,7 @@ which means that the length of each
|
|||
codeword is the same.
|
||||
For example, we can compress the string
|
||||
\texttt{AABACDACA} as follows:
|
||||
\[000001001011001000\]
|
||||
\[00\,00\,01\,00\,10\,11\,00\,10\,00\]
|
||||
Using this code, the length of the compressed
|
||||
string is 18 bits.
|
||||
However, we can compress the string better
|
||||
|
@ -496,7 +496,7 @@ An optimal code produces a compressed string
|
|||
that is as short as possible.
|
||||
In this case, the compressed string using
|
||||
the optimal code is
|
||||
\[001100101110100,\]
|
||||
\[0\,0\,110\,0\,10\,111\,0\,10\,0,\]
|
||||
so only 15 bits are needed instead of 18 bits.
|
||||
Thus, thanks to a better code it was possible to
|
||||
save 3 bits in the compressed string.
|
||||
|
@ -539,12 +539,12 @@ in the string,
|
|||
and each character's codeword can be read
|
||||
by following a path from the root to
|
||||
the corresponding node.
|
||||
A move to the left correspons to bit 0,
|
||||
A move to the left corresponds to bit 0,
|
||||
and a move to the right corresponds to bit 1.
|
||||
|
||||
Initially, each character of the string is
|
||||
represented by a node whose weight is the
|
||||
number of times the character appears in the string.
|
||||
number of times the character occurs in the string.
|
||||
Then at each step two nodes with minimum weights
|
||||
are combined by creating
|
||||
a new node whose weight is the sum of the weights
|
||||
|
|
97
luku07.tex
97
luku07.tex
|
@ -14,7 +14,7 @@ There are two uses for dynamic programming:
|
|||
|
||||
\begin{itemize}
|
||||
\item
|
||||
\key{Findind an optimal solution}:
|
||||
\key{Finding an optimal solution}:
|
||||
We want to find a solution that is
|
||||
as large as possible or as small as possible.
|
||||
\item
|
||||
|
@ -24,14 +24,14 @@ possible solutions.
|
|||
\end{itemize}
|
||||
|
||||
We will first see how dynamic programming can
|
||||
be used for finding an optimal solution,
|
||||
be used to find an optimal solution,
|
||||
and then we will use the same idea for
|
||||
counting the solutions.
|
||||
|
||||
Understanding dynamic programming is a milestone
|
||||
in every competitive programmer's career.
|
||||
While the basic idea of the technique is simple,
|
||||
the challenge is how to apply it for different problems.
|
||||
the challenge is how to apply it to different problems.
|
||||
This chapter introduces a set of classic problems
|
||||
that are a good starting point.
|
||||
|
||||
|
@ -47,7 +47,7 @@ In Chapter 6, we solved the problem using a
|
|||
greedy algorithm that always selects the largest
|
||||
possible coin.
|
||||
The greedy algorithm works, for example,
|
||||
when coins are euro coins,
|
||||
when the coins are the euro coins,
|
||||
but in the general case the greedy algorithm
|
||||
does not necessarily produce an optimal solution.
|
||||
|
||||
|
@ -60,15 +60,15 @@ that goes through all possibilities how to
|
|||
form the sum, like a brute force algorithm.
|
||||
However, the dynamic programming
|
||||
algorithm is efficient because
|
||||
it uses \emph{memoization} to
|
||||
calculate the answer to each subproblem only once.
|
||||
it uses \emph{memoization} and
|
||||
calculates the answer to each subproblem only once.
|
||||
|
||||
\subsubsection{Recursive formulation}
|
||||
|
||||
The idea in dynamic programming is to
|
||||
formulate the problem recursively so
|
||||
that the answer to the problem can be
|
||||
calculated from the answers for smaller
|
||||
calculated from answers to smaller
|
||||
subproblems.
|
||||
In the coin problem, a natural recursive
|
||||
problem is as follows:
|
||||
|
@ -107,8 +107,8 @@ and $f(5)=2$ because the sum 5 can
|
|||
be formed using coins 1 and 4.
|
||||
|
||||
The essential property in the function is
|
||||
that the value $f(x)$ can be calculated
|
||||
recursively from the smaller values of the function.
|
||||
that each value of $f(x)$ can be calculated
|
||||
recursively from smaller values of the function.
|
||||
For example, if the coin set is $\{1,3,4\}$,
|
||||
there are three ways to select the first coin
|
||||
in a solution: we can choose coin 1, 3 or 4.
|
||||
|
@ -133,9 +133,8 @@ In addition, it is convenient to define
|
|||
\[f(x)=\infty\hspace{8px}\textrm{if $x<0$}.\]
|
||||
This means that an infinite number of coins
|
||||
is needed for forming a negative sum of money.
|
||||
This prevents the situation that the recursive
|
||||
function would form a solution where the
|
||||
initial sum of money is negative.
|
||||
This prevents the function from constructing
|
||||
a solution where the initial sum of money is negative.
|
||||
|
||||
Once a recursive function that solves the problem
|
||||
has been found,
|
||||
|
@ -159,7 +158,7 @@ and the value $10^9$ denotes infinity.
|
|||
This function works but it is not efficient yet,
|
||||
because it goes through a large number
|
||||
of ways to construct the sum.
|
||||
However, the function becomes efficient by
|
||||
However, the function can be made efficient by
|
||||
using memoization.
|
||||
|
||||
\subsubsection{Memoization}
|
||||
|
@ -170,20 +169,20 @@ Dynamic programming allows us to calculate the
|
|||
value of a recursive function efficiently
|
||||
using \key{memoization}.
|
||||
This means that an auxiliary array is used
|
||||
for storing the values of the function
|
||||
for recording the values of the function
|
||||
for different parameters.
|
||||
For each parameter, the value of the function
|
||||
is calculated recursively only once, and after this,
|
||||
the value can be directly retrieved from the array.
|
||||
|
||||
In this problem, we can use the array
|
||||
In this problem, we can use an array
|
||||
\begin{lstlisting}
|
||||
int d[N];
|
||||
\end{lstlisting}
|
||||
|
||||
where $\texttt{d}[x]$ will contain
|
||||
the value $f(x)$.
|
||||
The constant $N$ should be chosen so
|
||||
the value of $f(x)$.
|
||||
The constant $N$ has to be chosen so
|
||||
that all required values of the function fit
|
||||
in the array.
|
||||
|
||||
|
@ -208,23 +207,23 @@ The function handles the base cases
|
|||
$x=0$ and $x<0$ as previously.
|
||||
Then the function checks if
|
||||
$f(x)$ has already been calculated
|
||||
and stored in $\texttt{d}[x]$.
|
||||
If $f(x)$ is found in the array,
|
||||
in $\texttt{d}[x]$.
|
||||
If the value of $f(x)$ is found in the array,
|
||||
the function directly returns it.
|
||||
Otherwise the function calculates the value
|
||||
recursively and stores it in $\texttt{d}[x]$.
|
||||
|
||||
Using memoization the function works
|
||||
efficiently, because the answer for each $x$
|
||||
efficiently, because the answer for each parameter $x$
|
||||
is calculated recursively only once.
|
||||
After a value of $f(x)$ has been stored in the array,
|
||||
it can be efficiently retrieved whenever the
|
||||
function will be called again with parameter $x$.
|
||||
function will be called again with the parameter $x$.
|
||||
|
||||
The time complexity of the resulting algorithm
|
||||
is $O(xk)$ where the sum is $x$ and the number of
|
||||
coins is $k$.
|
||||
In practice, the algorithm is usable if
|
||||
In practice, the algorithm can be used if
|
||||
$x$ is so small that it is possible to allocate
|
||||
an array for all possible function parameters.
|
||||
|
||||
|
@ -294,7 +293,7 @@ while (x > 0) {
|
|||
|
||||
\subsubsection{Counting the number of solutions}
|
||||
|
||||
Let us now consider a variation of the problem
|
||||
Let us now consider a variant of the problem
|
||||
that is otherwise like the original problem,
|
||||
but we should count the total number of solutions instead
|
||||
of finding the optimal solution.
|
||||
|
@ -319,7 +318,7 @@ The difference is that when finding the optimal solution,
|
|||
we maximize or minimize something in the recursion,
|
||||
but now we will calculate sums of numbers of solutions.
|
||||
|
||||
In the coin problem, we can define a function $f(x)$
|
||||
To solve the problem, we can define a function $f(x)$
|
||||
that returns the number of ways to construct
|
||||
the sum $x$ using the coins.
|
||||
For example, $f(5)=6$ when the coins are $\{1,3,4\}$.
|
||||
|
@ -330,7 +329,7 @@ because to form the sum $x$, we have to first
|
|||
choose some coin $c_i$ and then form the sum $x-c_i$.
|
||||
The base cases are $f(0)=1$, because there is exactly
|
||||
one way to form the sum 0 using an empty set of coins,
|
||||
and $f(x)=0$, when $x<0$, because it's not possible
|
||||
and $f(x)=0$, when $x<0$, because it is not possible
|
||||
to form a negative sum of money.
|
||||
|
||||
If the coin set is $\{1,3,4\}$, the function is
|
||||
|
@ -370,8 +369,8 @@ that it is not required to calculate the exact number
|
|||
but it is enough to give the answer modulo $m$
|
||||
where, for example, $m=10^9+7$.
|
||||
This can be done by changing the code so that
|
||||
all calculations are done in modulo $m$.
|
||||
In the above code, it is enough to add the line
|
||||
all calculations are done modulo $m$.
|
||||
In the above code, it suffices to add the line
|
||||
\begin{lstlisting}
|
||||
d[i] %= m;
|
||||
\end{lstlisting}
|
||||
|
@ -380,7 +379,7 @@ after the line
|
|||
d[i] += d[i-c[j]];
|
||||
\end{lstlisting}
|
||||
|
||||
Now we have covered all basic
|
||||
Now we have discussed all basic
|
||||
techniques related to
|
||||
dynamic programming.
|
||||
Since dynamic programming can be used
|
||||
|
@ -397,7 +396,7 @@ Given an array that contains $n$
|
|||
numbers $x_1,x_2,\ldots,x_n$,
|
||||
our task is to find the
|
||||
\key{longest increasing subsequence}
|
||||
in the array.
|
||||
of the array.
|
||||
This is a sequence of array elements
|
||||
that goes from left to right,
|
||||
and each element in the sequence is larger
|
||||
|
@ -496,8 +495,8 @@ where $i<k$ and $x_i<x_k$. In this case $f(k)=f(i)+1$.
|
|||
|
||||
For example, in the above example $f(7)=4$,
|
||||
because the subsequence $[2,5,7]$ of length 3
|
||||
ends at position 5, and after adding the element
|
||||
at position 7 to the subsequence,
|
||||
ends at position 5, and by adding the element
|
||||
at position 7 to this subsequence,
|
||||
we get the optimal subsequence $[2,5,7,8]$ of length 4.
|
||||
|
||||
An easy way to calculate the
|
||||
|
@ -514,7 +513,7 @@ Our next problem is to find a path
|
|||
in an $n \times n$ grid
|
||||
from the upper-left corner to
|
||||
the lower-right corner such that
|
||||
we can only move down and right.
|
||||
we only move down and right.
|
||||
Each square contains a number,
|
||||
and the path should be constructed so
|
||||
that the sum of numbers along
|
||||
|
@ -570,17 +569,17 @@ upper-left corner to the lower-right corner.
|
|||
|
||||
We can approach the problem by
|
||||
calculating for each square $(y,x)$
|
||||
the largest possible sum on a path
|
||||
the maximum sum on a path
|
||||
from the upper-left corner to square $(y,x)$.
|
||||
Let $f(y,x)$ denote this sum,
|
||||
so $f(n,n)$ is the largest sum on a path
|
||||
so $f(n,n)$ is the maximum sum on a path
|
||||
from the upper-left corner to
|
||||
the lower-right corner.
|
||||
|
||||
The recursive formula is based on the observation
|
||||
that a path that ends at square $(y,x)$
|
||||
can either come from square $(y,x-1)$
|
||||
or from square $(y-1,x)$:
|
||||
can come either from square $(y,x-1)$
|
||||
or square $(y-1,x)$:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=.65]
|
||||
\begin{scope}
|
||||
|
@ -682,7 +681,7 @@ denote the smallest possible total weight
|
|||
when a subset of objects
|
||||
$1 \ldots k$ is selected such
|
||||
that the total weight is $u$.
|
||||
The solution for the problem is the
|
||||
The solution to the problem is the
|
||||
largest value $u$
|
||||
for which $0 \le u \le s$ and $f(n,u) \le x$
|
||||
where $s=\sum_{i=1}^n a_i$.
|
||||
|
@ -711,8 +710,8 @@ depends on the values of the objects.
|
|||
|
||||
The \key{edit distance} or \key{Levenshtein distance}
|
||||
is the minimum number of editing operations
|
||||
needed for transforming the first string
|
||||
into the second string.
|
||||
needed to transform a string
|
||||
into another string.
|
||||
The allowed editing operations are as follows:
|
||||
\begin{itemize}
|
||||
\item insert a character (e.g. \texttt{ABC} $\rightarrow$ \texttt{ABCA})
|
||||
|
@ -721,10 +720,10 @@ The allowed editing operations are as follows:
|
|||
\end{itemize}
|
||||
|
||||
For example, the edit distance between
|
||||
\texttt{LOVE} and \texttt{MOVIE} is 2
|
||||
because we can first perform operation
|
||||
\texttt{LOVE} and \texttt{MOVIE} is 2,
|
||||
because we can first perform the operation
|
||||
\texttt{LOVE} $\rightarrow$ \texttt{MOVE}
|
||||
(change) and then operation
|
||||
(change) and then the operation
|
||||
\texttt{MOVE} $\rightarrow$ \texttt{MOVIE}
|
||||
(insertion).
|
||||
This is the smallest possible number of operations,
|
||||
|
@ -736,7 +735,7 @@ Suppose we are given strings
|
|||
$n$ and $m$ characters, respectively,
|
||||
and we wish to calculate the edit distance
|
||||
between them.
|
||||
This can be efficiently done using
|
||||
This can be done using
|
||||
dynamic programming in $O(nm)$ time.
|
||||
Let $f(a,b)$ denote the edit distance
|
||||
between the first $a$ characters of \texttt{x}
|
||||
|
@ -756,7 +755,7 @@ and in the general case the formula is
|
|||
where $c=0$ if the $a$th character of \texttt{x}
|
||||
equals the $b$th character of \texttt{y},
|
||||
and otherwise $c=1$.
|
||||
The formula considers all ways how to shorten the strings:
|
||||
The formula considers all possible ways to shorten the strings:
|
||||
\begin{itemize}
|
||||
\item $f(a,b-1)$ means that a character is inserted to \texttt{x}
|
||||
\item $f(a-1,b)$ means that a character is removed from \texttt{x}
|
||||
|
@ -819,7 +818,7 @@ in the example case:
|
|||
\end{center}
|
||||
|
||||
The lower-right corner of the table
|
||||
indicates that the edit distance between
|
||||
tells us that the edit distance between
|
||||
\texttt{LOVE} and \texttt{MOVIE} is 2.
|
||||
The table also shows how to construct
|
||||
the shortest sequence of editing operations.
|
||||
|
@ -889,7 +888,7 @@ the edit distance between \texttt{LOV} and \texttt{MOV}, etc.
|
|||
|
||||
\section{Counting tilings}
|
||||
|
||||
Sometimes the states in a dynamic programming solution
|
||||
Sometimes the states of a dynamic programming solution
|
||||
are more complex than fixed combinations of numbers.
|
||||
As an example,
|
||||
we consider the problem of calculating
|
||||
|
@ -971,9 +970,9 @@ so that the shorter side has length $m$,
|
|||
because the factor $4^{2m}$ dominates the time complexity.
|
||||
|
||||
It is possible to make the solution more efficient
|
||||
by using a better representation for the rows as strings.
|
||||
It turns out that it is sufficient to know the
|
||||
columns of the previous row that contain the first square
|
||||
by using a better representation for the rows.
|
||||
It turns out that it is sufficient to know which
|
||||
columns of the previous row contain the upper square
|
||||
of a vertical tile.
|
||||
Thus, we can represent a row using only characters
|
||||
$\sqcap$ and $\Box$, where $\Box$ is a combination
|
||||
|
|
Loading…
Reference in New Issue