115 lines
3.9 KiB
TeX
115 lines
3.9 KiB
TeX
\documentclass[10pt]{article}
|
|
\usepackage[utf8]{inputenc}
|
|
\usepackage{amsmath,amsthm,amssymb}
|
|
\usepackage{fullpage}
|
|
\usepackage{url}
|
|
\pagenumbering{gobble}
|
|
\usepackage{hyperref}
|
|
\usepackage{graphicx}
|
|
\input{statement/preamble.tex}
|
|
|
|
\title{ Tutorial: Maior Subsequência Comum}
|
|
\author{}
|
|
\date{}
|
|
\begin{document}
|
|
\maketitle
|
|
\section{Solução do Problema}
|
|
|
|
O problema da maior subsequência comum (\textit{Longest Common Subsequence}, LCS) pode ser resolvido por meio de \textit{programação dinâmica}.
|
|
A ideia central é decompor o problema em subproblemas menores, de forma que a solução ótima final seja construída a partir das soluções ótimas desses subproblemas.
|
|
|
|
\subsection{Definição do Subproblema}
|
|
|
|
Sejam duas strings \( s_1 \) e \( s_2 \), de tamanhos \( n \) e \( m \), respectivamente.
|
|
Definimos:
|
|
|
|
\[
|
|
dp[i][j] = \text{o comprimento da maior subsequência comum entre } s_1[1..i] \text{ e } s_2[1..j].
|
|
\]
|
|
|
|
Isto é, \( dp[i][j] \) representa a resposta do problema considerando apenas os primeiros \( i \) caracteres de \( s_1 \) e os primeiros \( j \) caracteres de \( s_2 \).
|
|
|
|
\subsection{Função de Transição}
|
|
|
|
Ao analisar um par de posições \( (i, j) \), temos duas possibilidades principais:
|
|
|
|
\begin{itemize}
|
|
\item Se os caracteres atuais são iguais, isto é, \( s_1[i] = s_2[j] \), então podemos estender uma subsequência comum encontrada anteriormente:
|
|
\[
|
|
dp[i][j] = dp[i-1][j-1] + 1.
|
|
\]
|
|
|
|
\item Caso contrário, não é possível usar ambos os caracteres ao mesmo tempo, então devemos escolher o melhor resultado entre ignorar um dos dois:
|
|
\[
|
|
dp[i][j] = \max(dp[i-1][j], \, dp[i][j-1]).
|
|
\]
|
|
\end{itemize}
|
|
|
|
Assim, a função de transição pode ser resumida como:
|
|
|
|
\[
|
|
dp[i][j] =
|
|
\begin{cases}
|
|
dp[i-1][j-1] + 1, & \text{se } s_1[i] = s_2[j] \\
|
|
\max(dp[i-1][j], \, dp[i][j-1]), & \text{caso contrário}
|
|
\end{cases}
|
|
\]
|
|
|
|
\subsection{Casos Base}
|
|
|
|
Os casos base seguem a lógica natural do problema:
|
|
|
|
\[
|
|
dp[0][j] = 0 \quad \forall j \ge 0
|
|
\]
|
|
\[
|
|
dp[i][0] = 0 \quad \forall i \ge 0
|
|
\]
|
|
|
|
Isto representa que, se uma das strings tiver tamanho zero, nenhuma subsequência comum pode ser formada.
|
|
|
|
\subsection{Recuperação da Subsequência Comum}
|
|
|
|
Após o preenchimento da matriz \( dp \), o valor \( dp[n][m] \) fornece o comprimento da maior subsequência comum entre \( s_1 \) e \( s_2 \).
|
|
No entanto, para obter também a subsequência em si, é necessário realizar um processo de \textit{backtracking} sobre a matriz.
|
|
|
|
A ideia consiste em iniciar a partir da posição \( (n, m) \) da matriz e caminhar em direção à origem.
|
|
Em cada passo:
|
|
|
|
\begin{itemize}
|
|
\item Se \( s_1[i] = s_2[j] \), então este caractere faz parte da LCS. Nesse caso, retrocedemos para \( (i-1, j-1) \).
|
|
\item Caso contrário, avançamos para o vizinho que contém o maior valor entre \( dp[i-1][j] \) e \( dp[i][j-1] \), pois esse vizinho indica o caminho que manteve o comprimento máximo da subsequência.
|
|
\end{itemize}
|
|
|
|
Como a subsequência é reconstruída de trás para frente, os caracteres encontrados devem ser adicionados no início da string resultante.
|
|
|
|
O algoritmo para recuperar uma subsequência comum de comprimento máximo é o seguinte:
|
|
|
|
\begin{verbatim}
|
|
int i = n; // ponteiro para s1
|
|
int j = m; // ponteiro para s2
|
|
string lcs = ""; // subsequência comum sendo reconstruída
|
|
|
|
// Enquanto ainda houver caracteres a considerar
|
|
while (i > 0 && j > 0) {
|
|
|
|
// Caso 1: os caracteres são iguais → fazem parte da LCS
|
|
if (s1[i - 1] == s2[j - 1]) {
|
|
lcs = s1[i - 1] + lcs; // adiciona no início da string
|
|
i--;
|
|
j--;
|
|
}
|
|
// Caso 2: se o valor de cima é maior, movemos para cima
|
|
else if (dp[i - 1][j] > dp[i][j - 1]) {
|
|
i--;
|
|
}
|
|
// Caso 3: caso contrário, movemos para a esquerda
|
|
else {
|
|
j--;
|
|
}
|
|
}
|
|
|
|
\end{verbatim}
|
|
|
|
Ao final desse processo, a string \texttt{lcs} conterá uma maior subsequência comum entre as duas strings.\end{document}
|