• Nenhum resultado encontrado

1 se n = 0 n (n 1)! se n 1

N/A
N/A
Protected

Academic year: 2021

Share "1 se n = 0 n (n 1)! se n 1"

Copied!
28
0
0

Texto

(1)

Recurs˜

ao versus Itera¸

ao

[ePD94, Cap. 5.13-15] Problema: C´alculo de n! = n × (n − 1) × . . . × 1 int facti(int n) { int fac=n; while(n>0){ fac=fac*n; n--; } return fac; } Defini¸c˜ao recursiva: n! =  1 se n = 0 n × (n − 1)! se n ≥ 1 int factr(int n){ if(n==0) return(1); else return(n*factr(n-1)); }

(2)

Chamadas recursivas e valores retornados

de cada chamada

Suponhamos n = 5 5! 5*4! 4*3! 3*2! 2*1! 1*0! 1 5! 5*4! 4*3! 3*2! 2*1! 1*0! 1 1 1*1=1 2*1=2 3*2=6 4*6=24 5*24=120

(3)

Paradigmas

Paradigma iterativo:

uma sequˆencia de instru¸c˜oes ´e excutada duma forma repetitiva, controlada por uma dada condi¸c˜ao (p.e. decremento de um contador)(ciclo iterativo).

Paradigma recursivo:

1. existˆencia de casos simples, em que a resposta ´e determinada directamente; 2. ser poss´ıvel uma decomposi¸c˜ao duma instˆancia do problema, em instˆancias mais

simples da mesma forma.

3. repeti¸c˜ao por chamadas sucessivas: numa fun¸c˜ao recursiva, s˜ao criadas v´arias activa¸c˜oes dela pr´opria que desaparecem h´a medida que a execu¸c˜ao avan¸ca. Em cada momento apenas uma das activa¸c˜oes est´a activa, estando as restantes `a espera que essa termine para continuarem.

(4)

Equivalˆencia entre os paradigmas Os dois paradigmas s˜ao equivalentes: dada uma fun¸c˜ao recursiva existe sempre uma iterativa e vice-versa.

(5)

Escrever a representa¸

ao dum inteiro n na base b.

Fun¸c˜ao Iterativa

void num_b_ite(int n,int b) {

if (n<0) { printf("-"); n= -n;}

if(n==0) {printf("%d",n); return;}

while(n) { printf("%d",n%b); n=n/b; } } Fun¸c˜ao Recursiva:

void num_b(int n,int b) {

if (n<0) {printf("-");n= -n;} if(n/b) num_b(n/b,b);

printf("%d",n%b); }

(6)

Estas fun¸c˜oes n˜ao s˜ao exactamente equivalentes! Porquˆe? Como torn´a-las equiva-lentes?

(7)

Sequˆ

encia de Fibonacci

(outra vez...)

0 1 1 2 3 5 8 13 21 34 55 89 144 . . .

Come¸cando com 0 e 1, cada termo seguinte ´e a soma dos dois anteriores Assim o n-´esimo termo ´e calculado por

fn = fn−1 + fn−2 e f0 = 0 e f1 = 1.

Ent˜ao, escrever uma fun¸c˜ao recursiva ´e imediato int fib(int n) {

if(n==0 || n==1) return n; return fib(n-1)+fib(n-2); }

Segue a execu¸c˜ao para f(4);. Como ´e uma vers˜ao iterativa?

(8)

O Puzzle das Torres de Hanoi

(inventado por Eduoard Lucas (1880))                                                                                                                                                                  

S˜ao dados trˆes suportes (a, b e c) e n discos de tamanhos diferentes.Os discos

est˜ao empilhados num dos suportes por ordem crescente de tamanhos.Pretende-se

mover os discos para outro suporte de modo que:

• em cada passo exactamente um disco seja movido de um suporte para o outro

• um disco n˜ao pode nunca estar por cima de um menor

(9)

Algoritmo (Fun¸

ao recursiva)

1. Representar cada suporte por um caracter (’a’, ’b’ e ’c’). Pretende-se uma fun¸c˜ao recursiva:

void hanoi(int n, char inicio, char fim, char temp);

2. Escrever uma fun¸c˜ao moveUm(char ini, char fim) que move a pe¸ca do cimo

do suporte ini para o suporte fim. moveUm(char ini, char fim){

printf("%c-> %c",ini,fim); }

(10)

3. A fun¸c˜ao hanoi() fica:

void hanoi(int n, char inicio, char fim, char temp) { if (n==1) moveUm(inicio,fim); else { hanoi(n-1,inicio,temp,fim); moveUm(inicio,fim); hanoi(n-1,temp,fim,inicio); } }

(11)

Execu¸

ao

%hanoi 3 a-> b a-> c b-> c a-> b c-> a c-> b a-> b %

O algoritmo ´e expon^encial O(2n): O n´umero de movimentos ´e exponencial com n,

Tn = 2Tn−1 + 1

isto ´e,

Tn = 2n − 1

(12)

etodo de ordena¸

ao Quicksort

C.A.R.Hoare 1960

56 25 37 58 95 19 73

M´etodo: Dada uma sequˆencia de valores, escolhe-se um elemento (pivot) e os

restantes valores s˜ao reagrupados em duas subsequˆencias (parti¸c˜ao):

• os que s˜ao menores que esse elemento

• os que s˜ao maiores.

O mesmo processo ´e aplicado recursivamente a cada subsequˆencia.Quando um

subconjunto tem menos que 2 elementos a recurs˜ao p´ara. Vamos escolher sempre o elemento do meio, como pivot.

(13)

void quicksort(int v[], int esq, int dir){ int i; if(esq>=dir) return ; i=particao(v,esq,dir); quicksort(v,esq,i-1); quicksort(v,i+1,dir); }

int particao(int v[],int esq,int dir){ int i, fim;

troca(v,esq,(esq+dir)/2); fim=esq;

for(i=esq+1;i<=dir;i++) if(v[i]<v[esq]) troca(v,++fim,i); troca(v,esq,fim);

return fim;

void troca(int v[], int i,int j){ int temp;

(14)

Execu¸

ao

Subvector: 56 25 37 58 95 19 73 Pivot: 58 Particao esq: 19 25 37 56 58 Particao dir: 95 73 Subvector: 19 25 37 56 Pivot: 25 Particao esq: 19 Particao dir: 37 56 Subvector: 37 56 Pivot: 37 Particao esq: Particao dir: 56 Subvector: 95 73 Pivot: 95 Particao esq: 73 Particao dir:

(15)
(16)

Quicksort para ordenar uma vari´

avel

indexada de strings

void quicksort_s(char v[][MAXCOL],int esq, int dir){ int i;

if(esq>=dir) return;

i=particao_s(v,esq,dir);

quicksort_s(v,esq,fim-1); quicksort_s(v,fim+1,dir); }

void particao(char v[][MAXCOL], int esq,int dir) { int i,fim;

troca_s(v,esq,(esq+dir)/2); fim=esq;

for(i=esq+1;i<=dir;i++) if(strcmp(v[i],v[esq])<0) troca_s(v,++fim,i); troca_s(v,esq,fim);

returm fim;}

void troca_s(char v[][MAXCOL], int i,int j) { char temp[MAXCOL];

(17)

indexada de strings. 

Exerc´ıcio 10.2. Escreve uma fun¸c˜ao recursiva que implemente o m´etodo de

ordena¸c˜ao por sele¸c˜ao. 

Exerc´ıcio 10.3. Escreve uma fun¸c˜ao recursiva que dado n e k determine a

potˆencia k de n. 

Exerc´ıcio 10.4. Escreve uma fun¸c˜ao recursiva que determine o m´aximo divisor

comun entre dois inteiros. 

Exerc´ıcio 10.5. Escreve uma fun¸c˜ao recursiva que gere todas as permuta¸c˜oes

(18)

Retrocesso na Resolu¸

ao de Problemas de

Pesquisa

Para muitos problemas, o m´etodo de resolu¸c˜ao consiste em percorrer uma sequˆencia de decis˜oes, cada uma fazendo avan¸car no caminho para a solu¸c˜ao. Se se fizerem as escolhas correctas chega-se a uma solu¸c˜ao sen˜ao tem de ser retrocecer e escolher outros caminhos.

• Divis˜ao em subtarefas

• Pesquisar exaustivamente um ´arvore de sub-tarefas

• Uso de Recurs˜ao Exemplos:

(19)

• procura da sa´ıda de um labirinto

• procura de um caminho numa rede que liga v´arios pontos

INCONVENIENTE: O tamanho da ´arvore de pesquisa cresce exponencialmente

com o tamanho dos dados

A saltar vai a todo o lado ...

Problema: dado um tabuleiro n × n determinar se um cavalo – do jogo de xadrez – consegue percorrer todas as posi¸c˜oes do tabuleiro, uma s´o vez,em n2 − 1 movimentos.

Estado Inicial: uma posi¸c˜ao do tabuleiro Estado Final: Ter visitado todas as posi¸c˜oes

Mudan¸ca de Estado: salto em “L” 2 por 1, de uma posi¸c˜ao para outra (candidata) Movimento v´alido: se existe uma posi¸c˜ao para saltar e essa posi¸c˜ao ainda n˜ao foi visitada

(20)

3 2

4 1

C

5 8

(21)

Algoritmo de Procura com Retrocesso

(Backtracking)

tenta

inicializa sele¸c˜ao de candidaos repete

seleciona um candidato

se aceit´avel marcar posi¸c˜ao se n˜ao estado final

tenta o passo seguinte

se n˜ao sucedeu retira marca da posi¸c˜ao

at´e estado final ou n˜ao haver mais candidatos Importante: N´umero de candidatos ´e finito!!!

(22)

Salto de Cavalo – I

int h[10][10], tab_max; main(){ int i,j;

do {

printf(" Tamanho do tabuleiro[3-10]: "); scanf("%d",&tab_max);

for(i=1;i<=tab_max; i++) for(j=1;j<=tab_max; j++) h[i][j]=0; printf("Posicao inicial:\n"); printf("Linha: "); scanf("%d",&i); printf("Coluna: "); scanf("%d",&j); h[i][j]=1; if (try(2,i,j)==1) for(i=1;i<=tab_max;i++) {

for(j=1;j<=tab_max;j++) printf("%d ",h[i][j]); printf("\n \n");}

else printf("Nao ha solucao \n"); printf("Ctrl C para terminar \n"); } while(getchar() !=EOF);

(23)

#define tab_sq tab_max*tab_max

#define in_tab(x) (x>0 && x<=tab_max) int casasx[]={2,1,-1,-2,-2,-1,1,2}; int casasy[]={1,2, ,2, 1,-1,-2,-2,-1}; int try(int i,int x,int y){

int k = 0, u, v; while( k < 8 ){

u=x+casasx[k]; v=y+casasy[k]; if(in_tab(u) && in_tab(v))

if (h[u][v] == 0) { h[u][v]=i; if (i >= tab_sq) return 1; if (try(i+1,u,v)==1) return 1; h[u][v]=0; } k++; } return 0;}

(24)

Tamanho do tabuleiro[3-10]: 5 Posicao inicial: Linha: 1 Coluna: 1 1 6 15 10 21 14 9 20 5 16 19 2 7 22 11 8 13 24 17 4 25 18 3 12 23 Ctrl C para terminar Tamanho do tabuleiro[3-10]: 5 Posicao inicial: Linha: 3 Coluna: 3 23 10 15 4 25 16 5 24 9 14 11 22 1 18 3 6 17 20 13 8 21 12 7 2 19 Ctrl C para terminar ^C

(25)

tabuleiro de xadrez (8x8) por forma a que n˜ao se ataquem mutuamente, isto ´e,

que n˜ao haja duas rainhas numa mesma linha, coluna ou diagonal? 

Sugest˜ao: Considere uma vari´avel indexada v[8] tal que v[i] corresponde `a linha em que estar´a a rainha da coluna i. A condi¸c˜ao para que duas rainhas estejam na mesma linha ´e:

#define linha(i,j) v[i] == v[j] e na mesma diagonal ´e

#define abs(x) (x >= 0? x: -x)

#define diagonal(i,j) abs(v[i]-v[j]) == abs(i-j) Podemos tentar gerar uma solu¸c˜ao:

• colocando aleat´oriamente valores de 0 a 8 (todos distintos) em v[] e depois ver se as condi¸c˜oes anteriores se verificam para todos. Para cada hip´otese h´a 56 testes e h´a 88 hip´oteses... o m´etodo ´e muito ineficiente

• Tentar gerar uma solucao da esquerda para a direita, come¸cando por fazer: i=0 -> v(i)=0

(26)

i=1 -> procurar o primeiro valor que

satisfaca as condicoes,i.e, v[1]=2

Em geral para cada i, se existe j > v[i] que satisfaz as condi¸c˜oes relativamente `as rainhas j´a colocadas, fazemos v[i]=j e passa-se para o i seguinte. Sen˜ao existe tal j, volta-se ao i anterior e tenta-se aplicar o processo.

(27)

Leituras

(28)

Referˆ

encias

[Bro97] J. Glenn Brookshear. Computer Science, an overview. Addison-Wesley, 1997.

[ePD94] H.M. Deitel e P.J. Deitel. C:How to Program. Prentice Hall International Editions, 2 edition, 1994.

Referências

Documentos relacionados

Aos trinta dias do mês de julho de dois mil e treze, às quatorze horas, na Sala de Reuniões do Prédio da Administração do Centro de Ciências Humanas e

- Verifique a necessidade de vacinas exigidas para cada país antes de visitá-lo;. - Em caso de necessidade de apresentação de Certificado Internacional de Vacina Contra Febre Amarela,

chamam a atenção para o facto de o acesso a fontes de energia sustentáveis e a existência de preços de energia acessíveis constituírem um verdadeiro desafio para os países ACP;

Código Descrição Atributo Saldo Anterior D/C Débito Crédito Saldo Final D/C. Este demonstrativo apresenta os dados consolidados da(s)

Os dados quantitativos ainda que não sejam as únicas ou preferenciais balizas para a qualidade dos museus, são imprescindíveis para possibilitar à gestão do museu projetar

A possibilidade de mobilidade combinada com a comunicação entre usuários apresenta-se como característica determinante da tecnologia de sistemas móveis. Os projetos apresentados

A rubrica “Aplicações para garantia de depósitos” enquadra os ativos fi nanceiros que servem de garantia dos depósitos constituídos nas CCAM participantes no FGCAM, de acordo com

Os resultados das regressões, que explicaram as eficiências dos produtores, mostraram que o tamanho das fazendas tem um impacto negativo sobre a eficiência técnica dos produtores