• 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

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

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,

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

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

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)

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