• Nenhum resultado encontrado

Programação Orientada pelos Objectos. Vigésima oitava aula: O problema dos degraus

N/A
N/A
Protected

Academic year: 2022

Share "Programação Orientada pelos Objectos. Vigésima oitava aula: O problema dos degraus"

Copied!
24
0
0

Texto

(1)

Programação Orientada pelos

Objectos

Vigésima oitava aula:

O problema dos degraus

(2)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 2

Nesta aula vamos…

• Primeiro, resolver o “problema dos degraus”, trabalhando pouco.

• Depois, resolver o “problema dos

degraus”, trabalhando um pouco mais para o computador trabalhar menos.

• Finalmente, resolver o “problema dos degraus” mais uma vez, para que os dois trabalhemos menos ☺

(3)

09-05-2007

O problema dos degraus

• À porta de casa do João há uma

escada com 10 degraus. João é um

rapaz ginasticado e consegue subir as escadas com passadas de um degrau ou de dois degraus. De quantas

maneiras diferentes pode o João subir a sua escada?

(4)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 4

Outra maneira de ver

• O problema é equivalente a descobrir de quantas maneiras diferentes podemos adicionar 1 e 2, várias vezes cada,

somando 10.

• Por exemplo 1+2+2+1+1+2+1 = 10

corresponde às somas parciais 0, 1, 3, 5, 6, 7, 9, 10.

• Todas as somas parciais começam em zero e acabam em 10, e cada uma delas representa uma maneira de subir as

escadas.

(5)

09-05-2007

Generalizando um pouco

• Para o problema ser mais interessante, vamos considerar que a escada tem N degraus e que a passada máxima do João é P.

• Ou seja, de quantas maneiras

podemos somar os números 1, … P, dando N?

(6)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 6

O grafo dos degraus

• Se o João estiver no degrau X, para que degraus pode subir? Para o degrau X+1 e para o degrau X+2 (se estes valores não forem maiores que 10).

• O rés-do-chão é 0 e o último degrau é 10.

0

1

2

3 4 5 6

7

8 9

10

(7)

09-05-2007

Estratégia

• Construímos o grafo, calculamos todos os caminhos e contamos quantos são.

• Recorremos às classes Graph e AllPaths.

• A única parte delicada é a construção do grafo.

• Resolvemos o problema com a classe Steps.

(8)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 8

Classe Steps

public class Steps {

private int steps;

private int jump;

private Graph graph;

private ArrayList<ArrayList<Integer>> paths;

public Steps(int steps, int jump) {

this.steps = steps;

this.jump = jump;

makeGraph();

// System.out.println(graph);

} }

private void makeGraph() {

graph = new Graph(steps+1);

for (int i = 0; i < steps; i++)

for (int j = 1; j <= jump && i+j <= steps; j++) graph.connect(i, i+j);

}

public void compute() {

AllPaths ap = new AllPaths(graph);

ap.compute(0, steps);

paths = ap.getPaths();

}

public int solution() {

return paths.size();

}

(9)

09-05-2007

Testando

public static void testSteps() {

Scanner in = new Scanner(System.in);

PrintWriter out = new PrintWriter(System.out, true);

while (in.hasNext()) {

int x = in.nextInt();

int y = in.nextInt();

Steps s = new Steps(x, y);

s.compute();

ArrayUtil.writeln(out, s.getPaths(), ArrayUtil.NEWLINE);

out.println(s.solution());

} }

5 2

[0, 1, 2, 3, 4, 5]

[0, 1, 2, 3, 5]

[0, 1, 2, 4, 5]

[0, 1, 3, 4, 5]

[0, 1, 3, 5]

[0, 2, 3, 4, 5]

[0, 2, 3, 5]

[0, 2, 4, 5]

8 7 3

[0, 1, 2, 3, 4, 5, 6, 7]

[0, 1, 2, 3, 4, 5, 7]

[0, 1, 2, 3, 4, 6, 7]

[0, 1, 2, 3, 4, 7]

[0, 1, 2, 3, 5, 6, 7]

[0, 1, 2, 3, 5, 7]

[0, 1, 2, 4, 5, 7]

[0, 1, 2, 4, 6, 7]

...

[0, 3, 4, 6, 7]

[0, 3, 4, 7]

[0, 3, 5, 6, 7]

[0, 3, 5, 7]

[0, 3, 6, 7]

44 10 2

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

[0, 1, 2, 3, 4, 5, 6, 7, 8, 10]

[0, 1, 2, 3, 4, 5, 6, 7, 9, 10]

...

[0, 2, 4, 6, 7, 9, 10]

[0, 2, 4, 6, 8, 9, 10]

[0, 2, 4, 6, 8, 10]

89

(10)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 10

O grafo dos degraus é acíclico

• Isto é, partindo de um vértice, é impossível regressar a ele.

• Logo, poderíamos simplificar a função visit em AllPaths:

public void visit(int x) {

path.push(x);

// visited[x] = true;

if (x == destination)

paths.add(new ArrayList<Integer>(path));

else

for (int y : graph.successors(x)) // if (!visited[y])

visit(y);

// visited[x] = false;

path.pop();

}

(11)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 11

Dispensando o grafo

• Vendo bem, podemos dispensar o grafo, observando que no ciclo for as únicas

ligações que se aproveitam são as de x para x+1, ..., x+jump.

public class StepsSimple {

private int steps;

private int jump;

private ArrayList<ArrayList<Integer>> paths;

public StepsSimple(int steps, int jump) {

this.steps = steps;

this.jump = jump;

}

• Fazemos isso numa nova

classe,

StepsSimple:

(12)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 12

Calculando os caminhos, sem grafo

public void compute() {

paths = new ArrayList<ArrayList<Integer>>();

path = new Stack<Integer>(steps + 1);

visit(0);

} public void visit(int x) {

path.push(x);

if (x == steps)

paths.add(new ArrayList<Integer>(path));

else

for (int i = 1; i <= jump && x + i <= steps; i++) visit(x + i);

path.pop();

}

(13)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 13

Contando os caminhos

• Se só quisermos contar, podemos simplificar ainda mais:

public void count() {

countPaths = 0;

visitCounting(0);

} public void visitCounting(int x) {

if (x == steps) countPaths++;

else

for (int i = 1; i <= jump && x + i <= steps; i++) visitCounting(x + i);

}

(14)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 14

Complexidade

• Meçamos os tempos de execução:

public static void testTimingStepsSimple(

int from, int upto, int jump, int repetitions) {

for (int j = from; j <= upto; j++) {

Clock c = new Clock();

for (int i = 0; i < repetitions; i++) {

StepsSimple s = new StepsSimple(j, jump);

s.count();

}

long t = c.milliseconds();

System.out.println(t);

} }

testTimingStepsSimple(15, 30, 2, 100); testTimingStepsSimple(10, 25, 3, 100);

O tempo cresce exponencialmente:

quando o tamanho dos dados aumenta uma unidade, o tempo passa para o dobro (mais ou menos).

(15)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 15

Tabelando as soluções

public static void testStepsSimpleTable() {

{

Scanner in = new Scanner(System.in);

int n = in.nextInt();

int jump = in.nextInt();

for (int i = 0; i <= n; i++) {

StepsSimple s = new StepsSimple(i, jump);

s.count();

System.out.println(i + " " + s.getCountPaths());

} } }

Mas isto são os números de Fibonacci!

(16)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 16

Números de Fibonacci

• Todos os programadores conhecem a função de Fibonacci:

Fibonacci(0) = 0 Fibonacci(1) = 1

Fibonacci(x) = Fibonacci(x – 2) + Fibonacci(x – 1), se x 2

Programamos na classe

Fibonacci:

public class Fibonacci {

public static int at(int x) {

assert x >= 0;

return x == 0 ? 0 : x == 1 ? 1 : at(x-2) + at(x-1);

}

} Note bem: o número de caminhos quando há x degraus é Fibonacci.at(x+1).

(17)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 17

public int get(int x) {

assert x >= 0;

assert x <= MAX_FIBONACCI;

return table[x];

}

Precalculando

• Podemos precalcular, não são muitos:

public class Fibonacci {

public static final int MAX_FIBONACCI = 46;

private int[] table;

// … }

public Fibonacci() {

init();

}

private void init() {

table = new int[MAX_FIBONACCI +1];

table[0] = 0;

table[1] = 1;

for (int i = 2; i <= MAX_FIBONACCI ; i++) table[i] = table[i-2] + table[i-1];

}

Para mais de 46, o valor da função ultrapassa os

limites do tipo int.

Bem mais eficiente do que a função at.

(18)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 18

Calculando iterativamente

• Exercício clássico:

calcular números de Fibonacci

iterativamente:

public static int fib(int x) {

int previous = 1;

int result = 0;

for (int i = 1; i <= x; i++) {

int z = previous;

previous = result;

result += z;

}

return result;

}

(19)

09-05-2007

Problema dos degraus, de novo

• O problema é contar as maneiras de subir as escadas.

Podemos abordá-lo assim:

• Seja F(x) o número de maneiras diferentes de subir uma escada de x degraus, com uma passada máxima de 2.

• Suponhamos que já resolvemos o problema para todas as escadas com 1, 2, ..., x-1 degraus e que, portanto,

conhecemos F(1), F(2), ..., F(x-1). Então, quanto vale F(x)?

• Ora bem, para subir x degraus, ou se sobem x-1 degraus e depois mais um, ou se sobem x-2 degraus e depois mais dois, de uma vez.

• Logo: F(x) = F(x-1) + F(x-2). Além disso, F(1) = 1 e F(2) = 2, nitidamente.

• Logo: F(x) = Fibonacci.at(x+1).

(20)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 20

0 0 1 1 2 1 3 2 4 3 5 5 6 8 7 13 8 21 9 34 10 55 11 89 12 144 13 233 14 377 15 610 16 987 17 1597 18 2584 19 4181 20 6765 21 10946 22 17711 23 28657 24 46368 25 75025 26 121393 27 196418 28 317811 29 514229 30 832040 31 1346269 32 2178309 33 3524578

34 5702887 35 9227465 36 14930352 37 24157817 38 39088169 39 63245986 40 102334155 41 165580141 42 267914296 43 433494437 44 701408733 45 1134903170 46 1836311903 47 2971215073 48 4807526976 49 7778742049 50 12586269025 51 20365011074 52 32951280099 53 53316291173 54 86267571272 55 139583862445 56 225851433717 57 365435296162 58 591286729879 59 956722026041 60 1548008755920 61 2504730781961 62 4052739537881 63 6557470319842 64 10610209857723 65 17167680177565 66 27777890035288 67 44945570212853

68 72723460248141 69 117669030460994 70 190392490709135 71 308061521170129 72 498454011879264 73 806515533049393 74 1304969544928657 75 2111485077978050 76 3416454622906707 77 5527939700884757 78 8944394323791464 79 14472334024676221 80 23416728348467685 81 37889062373143906 82 61305790721611591 83 99194853094755497 84 160500643816367088 85 259695496911122585 86 420196140727489673 87 679891637638612258 88 1100087778366101931 89 1779979416004714189 90 2880067194370816120 91 4660046610375530309 92 7540113804746346429 93 12200160415121876738 94 19740274219868223167 95 31940434634990099905 96 51680708854858323072 97 83621143489848422977 98 135301852344706746049 99 218922995834555169026 100 354224848179261915075

Tabela

(21)

09-05-2007

Grande Fibonacci

• Para calcular números de Fibonacci grandes usamos a classe BigInteger:

public class FibonacciBig {

public static BigInteger fib(int x) {

BigInteger previous = BigInteger.ONE;

BigInteger result = BigInteger.ZERO;

for (int i = 1; i <= x; i++) {

BigInteger z = BigInteger.ZERO.add(previous);

previous = BigInteger.ZERO.add(result);

result = result.add(z);

}

return result;

} }

(22)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 22

Controlo

• Qual é a fórmula dos números de Fibonacci?

• Qual era o nome próprio de Fibonacci?

• O que é um grafo acíclico?

(23)

09-05-2007

Exercícios

• Calcule numericamente o limite do quociente dos pares de números de

Fibonacci consecutivos. Verifique que é (51/2+1)/2.

• Este é o número dourado, phi.

• Confirme que

Fib(x) = (phin – (– phi)-n / (2·phi – 1)

(24)

09-05-2007 Programação Orientada pelos Objectos-28 © Pedro Guerreiro 24

Na próxima aula

• Estudaremos os iteradores.

• Os iteradores representam sequências de objectos, que ficam disponíveis cada um após o outro.

Referências

Documentos relacionados

Designar os professores Erica Verícia Canuto de Oliveira Veras, matrícula nº 3229333, Anna Emanuella Nelson dos Santos Cavalcanti da Rocha, matrícula nº 2474994 e

Diferentes tipos de grafite foram analisados a fim de conhecer seus efeitos nas propriedades acústicas e no padrão das imagens e, com isso, avaliar sua possível

Medidas de largura e comprimento do pneumatóforo (vesícula gasosa flutuadora da colônia de caravela) foram realizadas com auxílio de paquímetro milimetrado para

Apresentou como resultados: perfil e classificação internacional do RAJ desenvolvido no INTO; plano de análise dos dados deste Registro, com variáveis relevantes

O surf, esporte mundialmente conhecido e parte importante da cultura de diversos países, vem sendo praticado desde a antiguidade e fortalecendo-se a cada ano com um

Tendo como entrada a lista de candidatos restritos que contem os índices das componentes do grafo juntamente com seus respectivos valores de peso total, é feita uma escolha

que o currículo, inventado na passagem do século Xvi para o século Xvii, não somente ordenou o modo de funcionar de universida- des e colégios, como trouxe um sentido maior

Esta equação permite-nos saber como varia a densidade em função da pressão para um gás ideal sujeito a condições em que a temperatura se mantém constante... (Reveja as