Você está na página 1de 4

Divisão e Conquista

Divisão e Conquista (do inglês Divide and Conquer) é uma técnica de projeto de algoritmos utilizada pela
primeira vez por Anatolii Karatsuba em 1960 no algoritmo de Karatsuba.

Esta técnica consiste em dividir um problema maior recursivamente em problemas menores até que o
problema possa ser resolvido diretamente. Então a solução do problema inicial é dada através da
combinação dos resultados de todos os problemas menores computados. Vários problemas podem ser
solucionados através desta técnica, como a ordenação de números através do algoritmo Merge Sort e a
transformação discreta de Fourier através da transformada rápida de Fourier. Outro problema clássico
que pode ser resolvido através desta técnica é a Torre de Hanoi.

A técnica soluciona o problema através de três fases:

1. Divisão: o problema maior é dividido em problemas menores e os problemas menores obtidos


são novamente divididos sucessivamente de maneira recursiva.
2. Conquista: o resultado do problema é calculado quando o problema é pequeno o suficiente.
3. Combinação: o resultado dos problemas menores são combinados até que seja obtida a solução
do problema maior.

Eficiência
O método da divisão e conquista produz um algoritmo eficiente se a fase de divisão e a fase da
combinação forem suficientemente rápidos.

Problemas que utilizam esta técnica podem tirar proveito de máquinas com múltiplos processadores
pois a fase de divisão em problemas menores proporciona uma divisão natural do trabalho. Cada um
dos problemas menores obtidos pode ser calculado separadamente em um processador sem depender
dos demais.
A solução por esta técnica também é eficiente no uso da memória cache pois ao final da fase de divisão
grande parte dos dados necessários para a fase de combinação já estão disponíveis na cache
proporcionando um acesso mais veloz aos dados. Porém o caráter recursivo das soluções acaba gerando
um trabalho de processamento maior devido ao uso de chamadas recursivas e o uso da pilha de
chamadas.

Algoritmo Genérico para o paradigma Divisão e Conquista


DivisãoeConquista(x)
if x é pequeno ou simples do
return resolver(x)
else
decompor x em conjuntos menores x 0, x1, … xn
for i ← 0 to n do
yi ← DivisãoeConquista(xi)
i ← i +1
combinar yi’s
return y

Algoritmos baseados em divisão e conquista são, em geral, recursivos.

Exemplos
Vejas alguns algoritmos que usam o método da divisão e conquista:

□ Busca binária: divide a instância em duas menores e resolve uma delas; a fase de combinação é
vazia.
□ Mergesort: divide a instância em duas menores (essa fase é muito rápida) e resolve as duas
instâncias menores; a fase de combinação é a que consome mais tempo.
□ Quicksort: a fase da divisão é lenta e produz duas instâncias menores; a fase de combinação é
muito rápida.
void quicksort (int v[], int p, int r)
{
if (p < r)
{
int j = particiona (v, p, r);
quicksort (v, p, j-1);
quicksort (v, j+1, r);
}
}

□ Algoritmo da mediana: a fase da divisão, que produz duas instâncias menores, é lenta; a fase da
conquista resolve uma dessas instâncias; a fase de combinação é muito rápida.
□ Algoritmo de Karatsuba: a fase da divisão é muito rápida e produz três instâncias menores; a
fase de combinação consiste em algumas operações aritméticas.

Aplicação de Divisão e Conquista em um algoritmo simples


O algoritmo para encontrar o maior número em um vetor de números inteiros pode ser implementado
de forma simples e intuitiva da seguinte maneira:
int maior(int v[], int n)
{
int maior = v[0];
for (int i=1; i < n; i++)
if ( v[i] > maior)
maior = v[i];
return maior;
}

Veja que esse algoritmo é simples e ingênuo. Além do mais tem toda característica para se aplicar a
abordagem de divisão e conquista.

A versão desse mesmo algoritmo implementado com a abordagem de divisão e conquista é a seguinte:
int maior_com_divisao_e_conquista(int v[], int i, int f)
{
int meio, m1, m2;
if ( (f-i) <= 1 )
{
return max(v[i], v[f]);
}
else
{
meio = (i+f)/2;
m1 = maior_com_divisao_e_conquista(v, i, meio);
m2 = maior_com_divisao_e_conquista(v, meio+1, f);
}
return max(m1, m2);
}

Você também pode gostar