-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaula2-complex.tex
316 lines (264 loc) · 10.5 KB
/
aula2-complex.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
%% formatação saída C++
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NOCOES DE COMPLEXIDADE -
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{Importância}
Além de dominar as diferentes técnicas de solução de problemas, também é importante saber analisar a complexidade da sua solução.
\begin{itemize}
\item[$\blacksquare$] Ninguém gosta de receber um \emph{Time Limit Exceeded}.
\end{itemize}
\end{block}
\begin{block}{}
\begin{table}
\begin{tabular}{|l|l|l|l|l|l|l|}
\hline
Tamanho da entrada & 10 & 20 & 50 & 100 & 1000 & 5000 \\ \hline
algoritmo 1 & 0.00s & 0.01s & 0.05s & 0.47s & 23.92s & 47min \\ \hline
algoritmo 2 & 0.05s & 0.05s & 0.06s & 0.11s & 0.78s & 14.22s \\ \hline
\end{tabular}
\caption{Tempos de execução de dois algoritmos fictícios}
\end{table}
\end{block}
\end{frame}
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{}
\begin{itemize}
\item[] A solução de um problema deve ser eficiente.
\item[] Dois possíveis jeitos de analisar a eficiência da sua solução:
\begin{itemize}
\bitem Implementar e executar medindo o tempo gasto (ou submeter e torcer pra não receber TLE).
\item[\checkmark] Pensar no algoritmo e analisar o mesmo antes de começar a codificar.
\end{itemize}
\end{itemize}
\end{block}
\begin{block}{}
Durante uma competição sabe-se os possíveis tamanhos da entrada. Supondo que um algoritmo foi pensado, algumas perguntas geralmente devem ser respondidas.
\begin{itemize}
\bitem Vale a pena implementar essa solução? Ela vai resolver o maior caso em tempo?
\bitem Sei mais de um algoritmo pra resolver um problema, qual devo implementar?
\end{itemize}
\end{block}
\end{frame}
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{Certo, é importante. Mas como analisar a complexidade?}
\begin{itemize}
\bitem Dois tipos de medida:
\begin{itemize}
\bitem Complexidade de Tempo -- nro. de operações executadas pelo algoritmo
\bitem Complexidade de Espaço -- quantidade de memória que o algoritmo usa durante a execução
\end{itemize}
\bitem Foco na análise da Complexidade de Tempo.
\begin{itemize}
\tiny
\bitem Geralmente se o algoritmo tem uma boa complexidade de tempo, ele também tem uma boa complexidade de espaço.
\bitem Costuma ser mais fácil estimar o espaço gasto.
\end{itemize}
\end{itemize}
\end{block}
\begin{block}{Casos a serem levados em consideração}
\begin{itemize}
\bitem Melhor caso
\bitem Caso médio
\item[\checkmark] Pior Caso
\end{itemize}
\end{block}
\end{frame}
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{Análise assimptótica}
\begin{itemize}
\bitem Considere o nro. de operações de cada um dos dois algoritmos fictícios que resolvem o mesmo problema uma função de $n$ (o ``tamanho'' da entrada)
\begin{itemize}
\bitem Algoritmo 1: $f_1(n) = 42n^2 + 13n$ operações
\bitem Algoritmo 2: $f_2(n) = 1337n + 666$ operações
\end{itemize}
\bitem Dependendo do valor de $n$ o Algoritmo 1 pode requerer mais ou menos operações que o Algoritmo 2.
\bitem Um caso de particular interesse é quando $n$ tem valor muito grande ($n \rightarrow \infty$), denominado comportamento assimptótico.
\bitem Os termos inferiores e as constantes multiplicativas contribuem pouco na comparação e podem ser descartados.
\end{itemize}
\end{block}
\end{frame}
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{Notação $O$}
\begin{itemize}
\item[] Dada uma função $g(n)$, denotamos por $O(g(n))$ o conjunto das funções\\
\begin{center}$\{f(n) : \exists$ constantes $c_1\ e\ n_0$ tais que $0 \leq f(n) \leq c_1g(n)$ para $n \geq n_0\}$\end{center}
\item[] Isto é, para valores de $n$ suficientemente grandes, $f(n)$ é menor ou igual a $g(n)$.
\begin{itemize}
\bitem Algoritmo 1: $f_1(n) = 42n^2 + 13n \in O(n^2)$
\bitem Algoritmo 2: $f_2(n) = 1337n + 666 \in O(n)$
\end{itemize}
\item[] Um polinômio de grau $d$ é de ordem $O(n^d)$. Como uma constante é considerada um polinômio de grau 0, dizemos que uma constante é $O(n^0)$, ou seja, $O(1)$.
\begin{itemize}
\tiny
\item[$\dagger$] $O(n) \times O(n) = O(n^2)$
\item[$\dagger$] $O(n) + O(n) = O(n)$
\item[$\dagger$] $O(n) + O(n^2) = O(n^2)$
\end{itemize}
\end{itemize}
\end{block}
\end{frame}
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{Exemplo: Selection Sort}
\begin{itemize}
\item[] Para cada posição $i$ com $i$ variando de $0$ até $n-2$ \uncover<4->{$O(n)$}
\begin{itemize}
\item[] Encontre a posição $j$, ($i \leq j < n$) onde está o menor elemento. \uncover<3->{$O(n)$}
\item[] Troque os valores das posições $i$ e $j$. \uncover<2->{$O(1)$}
\end{itemize}
\item[]<5-> $O(n) * (O(n) + O(1)) = O(n) * O(n) = O(n^2)$
\end{itemize}
\end{block}
\end{frame}
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{Exemplo: Sequência de Fibonacci}
\begin{center}\textbf{1, 1, 2, 3, 5, 8, 13, 21, 34, ...}\end{center}
\begin{itemize}
\item[] A sequência pode ser definida pela seguinte recorrência:
\item[] $$F_n = \begin{cases}
1&\text{se } n=1\\
1&\text{se } n=2\\
F_{n-1}+F_{n-2}&\text{se } n>2
\end{cases}$$
\end{itemize}
\end{block}
\end{frame}
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{Exemplo: Sequência de Fibonacci - Algoritmo 1}
\includefile{c++}{codes}{fib1.cpp}
\end{block}
\begin{block}{Exemplo: Sequência de Fibonacci - Algoritmo 2}
\includefile{c++}{codes}{fib2.cpp}
\end{block}
\end{frame}
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{Exemplo: Sequência de Fibonacci - Algoritmo 1}
\includefile{c++}{codes}{fib1.cpp}
\end{block}
\begin{block}{Qual a complexidade?}
\begin{itemize}
\bitem Inicialmente pode parecer que o número de operações dessa solução é constante, afinal no pior caso será feita uma verificação e uma soma.
\bitem Mas, não podemos esquecer que essa é uma função recursiva, então esse número constante de operações será executado em cada chamada da função recursiva.
\end{itemize}
\end{block}
\end{frame}
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{Exemplo: Sequência de Fibonacci - Algoritmo 1}
\includefile{c++}{codes}{fib1.cpp}
\end{block}
\begin{block}{Qual a complexidade?}
\begin{itemize}
\bitem E como saber quantas chamadas serão feitas numa função?
\begin{itemize}
\bitem $O(x)$ possíveis valores para o parâmetro $y$ da função,
\bitem $b$ possíveis escolhas em cada chamada (fator de ramificação)
\bitem $b^{O(x)}$ chamadas no pior caso
\end{itemize}
\bitem Para a solução em questão temos $O(2^n)$ possíveis chamadas com um custo $O(1)$
\bitem Complexidade da solução: $O(2^n)$
\end{itemize}
\end{block}
\end{frame}
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{Exemplo: Sequência de Fibonacci - Algoritmo 2}
\includefile{c++}{codes}{fib2.cpp}
\end{block}
\begin{block}{Qual a complexidade?}
$O(1)$ operações (\tiny \texttt{f[i] = f[i-1] + f[i-2];}\normalsize) sendo executadas $O(n)$ vezes.\\
Complexidade da solução: $O(n)$
\end{block}
\end{frame}
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{Exemplo: Sequência de Fibonacci - Algoritmo 2}
\includefile{c++}{codes}{fib2.cpp}
\end{block}
\begin{block}{Qual a complexidade?}
E a complexidade de espaço?
\begin{itemize}
\item[]<2-> $O(n)$
\item[]<3-> Será que dá pra fazer melhor?
\end{itemize}
\end{block}
\end{frame}
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{Exemplo: Sequência de Fibonacci - Uma terceira solução}
\includefile{c++}{codes}{fib3.cpp}
\end{block}
\begin{block}{Qual a complexidade?}
\begin{itemize}
\item[] Complexidade de Tempo: $O(n)$
\item[] Complexidade de Espaço: $O(1)$
\end{itemize}
\end{block}
\end{frame}
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{Exemplo: Busca num vetor ordenado}
Problema: Dado um vetor de $n$ inteiros distintos, com os elementos em ordem crescente,
encontrar a posição onde está o valor $x$, ou informar que o mesmo não existe no vetor.\\
\end{block}
\pause
\begin{block}{Solução 1:}
\begin{itemize}
\item[] Percorre o vetor comparando elemento por elemento até encontrar $x$
\item[] Se olhou todos os elementos e não encontrou, $x$ não está presente.\\
\bitem<3-> No pior caso todos os $n$ elementos são comparados
\bitem<3-> $O(n)$
\end{itemize}
\end{block}
\end{frame}
%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SLIDE -
\begin{frame}
\frametitle{Noções de Complexidade}
\begin{block}{Exemplo: Busca num vetor ordenado}
Problema: Dado um vetor de $n$ inteiros distintos, com os elementos em ordem crescente,
encontrar a posição onde está o valor $x$, ou informar que o mesmo não existe no vetor.\\
\end{block}
\begin{block}{Solução 2:}
Mas o vetor está ordenado, será que isso não ajuda?
\uncover<2->
{
\begin{itemize}
\tiny
\item[] Inicialmente procuramos nas posições \texttt{inicio = 0, fim = n-1}
\item[] enquanto inicio <= fim
\begin{itemize}
\tiny
\item[] \texttt{meio = (inicio+fim)/2}
\item[] se \texttt{array[ meio ] < x}, \texttt{inicio = meio + 1;}
\item[] se \texttt{array[ meio ] > x,} \texttt{fim = meio - 1;}
\item[] se \texttt{array[ meio ] == x}, Encontrou $x$ na posição 'meio'
\end{itemize}
\item[] $x$ não está presente no vetor
\normalsize
\bitem<3-> Como a faixa onde estamos buscando o valor vai ser sempre dividida ao meio, no máximo $O(log_2\ n)$ faixas são verificadas.
\bitem<3-> Complexidade da solução: $O(log\ n)$
\end{itemize}
}
\end{block}
\end{frame}