\documentclass[10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{amsmath,amsthm,amssymb}
\usepackage{fullpage}
\usepackage{url}
\pagenumbering{gobble}
\usepackage{hyperref}

\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}
