Universidade do Estado Santa Catarina - UDESC Departamento de Ciência da Computação - DCC Maratona Doméstica de Programação – 2008-1 (Claudete) 2 de junho de 2008 Lembrete: • É permitido consultar livros, anotações ou qualquer outro material impresso cópia durante a prova. • A correção é automatizada, portanto siga atentamente as exigências da tarefa quanto ao formato da entrada e saída de seu programa. • Todos os problemas têm o mesmo valor na correção. • Procure resolver o problema de maneira eficiente. Na correção, a eficiência também é levada em conta. As soluções serão testadas com outras entradas além das apresentadas como exemplo dos problemas. • Nas implementações, as entradas e as saídas conhecidas serão padrão (ler e escrever na saída padrão). • Utilize o Clarification para dúvidas da prova. Opcionalmente, os juízes respondem, contudo, as respostas são acessíveis a todos. • Dica geral da prova: “Os últimos serão os primeiros”! Agradecimentos • • • • • Parte desta prova foi elaborada por Wanderley Guimarães, coach dos times do IME-USP. André Guedes, coach dos times do UFPR. UDESC, DATASUL, Rede Globo, Google, Editora NOVATEC. Ao pessoal do suporte da UDESC e o Grupo Colméia. Ao DCC e demais anônimos que tornaram este evento uma realidade. Próxima Doméstica (ainda sem nome): 30/08/2008 (sábado) 1 Rascunho: 2 Problema A: Recuperação Arquivo: recuperacao.[c|cpp|java] A nossa grandiosa Professora Cris no último aquecimento ficou conhecida como a grande maquiavélica do IME. Para quem não está a par do assunto, a digníssima professora exigiu que os alunos formassem uma fila em ordem lexicográfica (pelo nome) com no máximo k permutações. Isto fez com que muitos alunos nem sequer entrassem na sala para fazer a prova. No entanto, nesta seletiva ela resolveu se redimir perante seus alunos, e resolveu aplicar um probleminha para recuperação. Sua tarefa, mesmo não tendo sido reprovado, é dada uma sequência de n inteiros a1 , a2 , .., an , P onde −30 ≤ aj ≤ 30 para j = 1, 2, .., n, imprima, se existir, um inteiro ak tal que ak = k−1 i=1 ai . Se houver mais de um inteiro que satisfaça esta condição, imprima o que aparece primeiro na seqüência. Cris: “Meninos, lembrem-se que a soma de nenhum número é zero! Tá?” Entrada A entrada é composta de diversas instâncias. A primeira linha de cada instância consiste em um inteiro n (1 ≤ n ≤ 100) indicando o número de inteiros na linha seguinte devem ser processados. A entrada termina com final de arquivo. Saída Para cada instância, você deverá imprimir um identificador Instancia k, onde k é o número da instância atual. Na linha seguinte imprima o inteiro que satisfaça a restrição descrita acima. Caso não exista tal inteiro imprima nao achei. Após cada instância imprima uma linha em branco. Exemplo de entrada 1 0 7 1 2 3 4 5 6 7 Exemplo de saída Instancia 1 0 Instancia 2 3 3 Problema B: Quem vai ser reprovado? Arquivo: placar.[c|cpp|java] Prof. Wallywow da Universidade da Columbia Britânica está muito preocupado com a queda do nível de atenção de seus estudantes. Ele já tentou várias técnicas mundialmente conhecidas para incentivar os alunos a prestar atenção nas suas aulas e fazer as tarefas que ele passa para a turma: deu nota para os alunos mais participativos, ofereceu chocolates aos alunos, levou seu karaokê e cantava nas aulas etc. Como tais medidas não levaram a uma melhora no comparecimento às aulas (a idéia do karaokê, inclusive, mostrou-se bastante infeliz. . . na segunda aula com karaokê a turma reduziu-se a um aluno – que tinha problemas auditivos) ele teve uma brilhante idéia: faria uma competição entre os alunos. Prof. Wallywow passou um conjunto de problemas aos alunos, e deu um mês para que eles os resolvessem. No final do mês os alunos mandaram o número de problemas resolvidos corretamente. A promessa do brilhante didata era reprovar sumariamente o último colocado da competição. Os alunos seriam ordenados conforme o número de problemas resolvidos, com empates resolvidos de acordo com a ordem alfabética dos nomes (não há homônimos na turma). Isso fez com que alunos com nomes iniciados nas últimas letras do alfabeto se esforçassem muito nas tarefas, e não compartilhassem suas soluções com colegas (especialmente aqueles cujos nomes começassem com letras anteriores). Sua tarefa neste problema é escrever um programa que lê os resultados dos alunos do Prof. Wallywow e imprime o nome do infeliz reprovado. Qualquer semelhança entre o Prof. Wallywow e o Prof. Carlinhos é mera coincidência. Entrada A entrada é composta de diversas instâncias. A primeira linha de cada instância consiste em um inteiro n (1 ≤ n ≤ 100) indicando o número de alunos na competição. Cada uma das n linhas seguintes contém o nome do aluno e o número de problemas resolvidos por ele. O nome consiste em uma seqüência de letras [a-z] com no máximo 20 letras e cada time resolve entre 0 à 10 problemas. A entrada termina com final de arquivo. Saída Para cada instância, você deverá imprimir um identificador Instancia k, onde k é o número da instância atual. Na linha seguinte imprima o nome do infeliz reprovado. Após cada instância imprima uma linha em branco. Exemplo de entrada 4 cardonha 9 infelizreprovado 3 marcel 9 infelizaprovado 3 Exemplo de saída Instancia 1 infelizreprovado 4 Problema C: Não é Mais um Joguinho Canadense! Arquivo: contagem.[c|cpp|java] O Canadá é um país muito frio. Em 8 meses por ano as temperaturas praticamente impedem que as ruas sejam ocupadas por vida inteligente, restando apenas criaturas resistentes ao frio como alces, ursos e canadenses1 . Nestes longos meses de inverno famílias buscam diversão em frente de suas lareiras (ou, para as mais corajosas, ao redor de suas fogueiras). A família Smith, de Banff, inventou o jogo que descrevemos a seguir. A brincadeira começa com uma das crianças desenhando um diagrama com estados (representados por bolinhas) ligados por transições (flechas ligando os estados). Cada transição tem uma letra e um número associados. Podemos fazer diversos passeios neste diagrama, partindo de um estado inicio caminhando por suas transições e terminando em um estado final. Um passeio forma uma palavra (obtida da concatenação das letras das transições percorridas) e tem um custo (que é dado pelo produto dos números destas transições). Exemplo. Considere o diagrama abaixo. 1b 1a p 1b 2b q 2a Figura 1: Diagrama Todos os passeios iniciam no estado p e terminam em q. O passeio que segue pelas transições (p,1a), (p,1a), (p,1b) e termina no estado q forma a palavra aab concatenando as letras de cada transição tem custo 1 (produto dos números destas transições). O passeio que segue pelas transições (p,1a), (p,1a), (p,1b), (q,2b) e termina no estado q forma a palavra aabb e tem custo 2. O jogo inventado pelo papai Smith era o seguinte. Depois de desenhar um diagrama como esse, um dos membros da família falava uma palavra, e os outros deveriam descobrir a soma dos custos de todos os passeios no diagrama que formam a palavra dada tais que iniciam no estado p e terminam no estado q. No caso do exemplo do diagrama acima, se o Sr. Smith pedisse a palavra aba a resposta deveria ser 2. Entrada A entrada é composta de diversas palavras (o diagrama é sempre o da figura). Cada instância é dada por uma linha contendo uma palavra. Uma palavra é uma seqüência de letras [a,b] com no máximo 60 letras. A entrada termina com final de arquivo. Saída Para cada instância, você deverá imprimir um identificador Palavra k, onde k é o número da instância atual. Na linha seguinte imprima a soma dos custos. Após cada instância imprima uma linha em branco. 1 He he he, brincadeirinha. . . 5 Exemplo de entrada a b ab ba aaaa bbbb aabb abbb Exemplo de saída Palavra 1 0 Palavra 2 1 Palavra 3 1 Palavra 4 2 Palavra 5 0 Palavra 6 15 Palavra 7 3 Palavra 8 7 6 Problema D: Collatz (3n + 1) Arquivo: collatz.[c|cpp|java] Considere o seguinte algoritmo para gerar uma seqüência de números: 1. Inciando com um inteiro n: se n é par divide-se por 2 2. Se n for ímpar, multiplica por 3 e adiciona 1 3. Repetindo este processo para o novo valor de n, terminando quando n = 1 Por exemplo: 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1 é uma conjectura (mas que não foi provada ainda), que este algoritmo sempre vai terminar com n = 1 para todo inteiro n < 1.000.000. Para uma entrada n, tamanho do ciclo de n é o número de números gerados pelo algoritmos incluindo 1 e o próprio n. No exemplo acima o tamanho do ciclo de 22 é 16. Dado quaisquer dois números i e j, você tem que determinar o maior tamanho do ciclo para todos os número entre i e j, inclusive. Entrada A entrada deve consistir em uma série de pares de inteiros i e j, sendo um par por linha. Todos o inteiros devem ser menor de 1.000.000 e maior do que 0. 1 10 100 200 201 210 900 1000 Saída Para cada par de inteiros i e j, mostrar i, j na mesma ordem em que eles aparecem na entrada, seguindo do maior tamanho do ciclo para todos os números entre i e j, inclusive. Esses três números devem ser separados por um espaço e todos os três números em um linha e com uma linha de saída para cada linha de entrada. 1 10 20 100 200 125 201 210 89 900 1000 174 7 Problema E: Romanes eunt domus? Arquivo romanes.[c|cpp|java] O Imperador da Roma antiga, Sírus Flavius Deunxarius queria montar uma nova representação de números em seu reino – que depois ficou conhecido como os números romanos. Mas como havia uma representação muito precária para milhões, ele resolveu criar um risco na letra para representar os milhões. Em um problema no espaço tempo Sírus acabou caíndo no futuro – aproximadamente daqui a 45 minutos próximo de Roma (dizem que ele caiu em um wormhole). Como ele não sabe muito bem de computadores, ele precisa converter binário ou hexadecimal para números Romanos para se situar melhor no mundo moderno. A sua tarefa é implementar um programa que realize esta tarefa para o nosso viajante no tempo2 . Arábico Romano Arábico Romano Arábico Romano Arábico Romano 1 I 10 X 90 XC 950 CML 2 II 15 XV 91 XCI 999 CMXCIX 3 III 20 XX 100 C 1000 M 4 IV 40 XL 500 D 5000 _V_ 5 V 50 L 555 DLV 1000000 _M_ Entrada A entrada consiste em um número N - binário puro ou um hexadecimal iniciado por x (“xis minúsculo”). O programa pára quando a entrada for zero. Com 0 < N < 10.000.000 xFB 11110100010011011001 111 x292 0 Saída A saída consiste no número em Romanos equivalente. CCLI _M_DCLXV VII DCLVIII 2 Não se preocupe, ele só passará 2 dias no futuro e voltará pro seu tempo - ele tem problemas com wormholes. 8 Problema F: Sudoku Arquivo: sudoku.[c|cpp|java] O jogo de Sudoku espalhou-se rapidamente por todo o mundo, tornando-se hoje o passatempo mais popular em todo o planeta. Muitas pessoas, entretanto, preenchem a matriz de forma incorreta, desrespeitando as restrições do jogo. Sua tarefa neste problema é escrever um programa que verifica se uma matriz preenchida é ou não uma solução para o problema. A matriz do jogo é uma matriz de inteiros 9 × 9. Para ser uma solução do problema, cada linha e coluna deve conter todos os números de 1 a 9. Além disso, se dividirmos a matriz em 9 regiões 3 × 3, cada uma destas regiões também deve conter os números de 1 a 9. O exemplo abaixo mostra uma matriz que é uma solução do problema. 1 4 7 6 5 9 2 3 8 3 9 5 4 2 8 1 6 7 2 8 6 3 1 7 4 5 9 5 2 3 1 7 4 9 8 6 7 6 8 5 9 2 3 1 4 9 1 4 8 3 6 5 7 2 4 3 2 7 8 5 6 9 1 6 7 1 9 4 3 8 2 5 8 5 9 2 6 1 7 4 3 Entrada São dadas várias instâncias. O primeiro dado é o número n > 0 de matrizes na entrada. Nas linhas seguintes são dadas as n matrizes. Cada matriz é dada em 9 linhas, em que cada linha contém 9 números inteiros. 2 1 4 7 6 5 9 2 3 8 1 4 7 6 5 9 2 3 8 3 9 5 4 2 8 1 6 7 3 9 5 4 2 8 1 6 7 2 8 6 3 1 7 4 5 9 2 8 6 3 1 7 4 5 9 5 2 3 1 7 4 9 8 6 5 2 3 1 7 4 9 8 6 7 6 8 5 9 2 3 1 4 7 6 8 5 9 2 3 1 4 9 1 4 8 3 6 5 7 2 9 1 4 8 3 6 5 7 2 4 3 2 7 8 5 6 9 1 4 3 2 7 8 5 6 9 1 6 7 1 9 4 3 8 2 5 6 7 1 9 4 3 8 2 3 8 5 9 2 6 1 7 4 3 8 5 9 2 6 1 7 4 5 Saída Para cada instância, imprima uma linha dizendo Instancia k, onde k é o número da instância atual. Na segunda linha, seu programa deverá imprimir SIM se a matriz for a solução de um problema de Sudoku, e NAO caso contrário. Imprima uma linha em branco após cada instância. 9 Instancia 1 SIM Instancia 2 NAO 10 Problema G: Cofrinhos da Vó Vitória Arquivo: cofre.[c|cpp|java] Vó Vitória mantém, desde o nascimento dos netos Joãozinho e Zezinho, um ritual que faz a alegria dos meninos. Ela guarda todas as moedas recebidas como troco em dois pequenos cofrinhos, um para cada neto. Quando um dos cofrinhos fica cheio, ela chama os dois netos para um alegre almoço, ao final do qual entrega aos garotos as moedas guardadas nos cofrinhos de cada um. Ela sempre foi muito zelosa quanto à distribuição igualitária do troco arrecadado. Quando, por força do valor das moedas, ela não consegue depositar a mesma quantia nos dois cofrinhos, ela memoriza a diferença de forma a compensá-la no próximo depósito. Tarefa Vó Vitória está cando velha e tem medo que deslizes de memória a façam cometer injustiças com os netos, deixando de compensar as diferenças entre os cofrinhos. Sua tarefa é ajudar Vó Vitória, escrevendo um programa de computador que indique as diferenças entre os depósitos, de forma que ela não tenha que preocupar-se em memorizá-las. Entrada A entrada é composta de vários conjuntos de teste. A primeira linha de um conjunto de teste contém um número inteiro N , que indica o número de depósitos nos cofrinhos. As N linhas seguintes descrevem cada uma um depósito nos cofrinhos; o depósito é indicado por dois valores inteiros J e Z, separados por um espaço em branco, representando respectivamente os valores, em centavos, depositados nos cofres de Joãozinho e Zezinho. O final da entrada é indicado por N = 0. Saída Para cada conjunto de teste da entrada seu programa deve produzir um conjunto de linhas na saída. A primeira linha deve conter um identicador do conjunto de teste, no formato “Teste n”, onde n é numerado seqüencialmente a partir de 1. A seguir seu programa deve escrever uma linha para cada depósito do conjunto de testes. Cada linha deve conter um inteiro que representa a diferença (em centavos) entre o valor depositado nos cofrinhos do Joãozinho e do Zezinho. Deixe uma linha em branco ao final de cada conjunto de teste. A grafia mostrada no Exemplo de Saída, abaixo, deve ser seguida rigorosamente. Exemplo Entrada: 3 20 25 10 5 10 10 4 0 5 12 0 0 20 17 1 0 Saída: 11 Teste 1 -5 0 0 Teste 2 -5 7 -13 3 Restrições 0 <= N <= 100 (N = 0 apenas para indicar o m da entrada) 0 <= J <= 100 (valor de cada depósito no cofre de Joãozinho) 0 <= Z <= 100 (valor de cada depósito no cofre de Zezinho) 12 Problema H: Estágio Arquivo: estagio.[c|cpp|java] Você conseguiu um estágio para trabalhar como programador na secretaria da sua escola. Como primeira tarefa, Dona Vilma, a coordenadora, solicitou que você aprimore um programa que foi desenvolvido pelo estagiário anterior. Esse programa tem como entrada uma lista de nomes e de médias finais dos alunos de uma turma, e determina o aluno com a maior média na turma. Dona Vilma pretende utilizar o programa para premiar o melhor aluno de cada turma da escola. O programa desenvolvido pelo estagiário anterior encontra-se no final deste enunciado (em C e C++). Como você pode verificar, o programa na forma atual tem uma imperfeição: no caso de haver alunos empatados com a melhor média na turma, ele imprime apenas o primeiro aluno que aparece na lista. Tarefa Dona Vilma deseja que você altere o programa para que ele produza uma lista com todos os alunos da turma que obtiveram a maior média, e não apenas um deles. Você consegue ajudá-la nesta tarefa? Entrada A entrada é constituída de vários conjuntos de teste, representando várias turmas. A primeira linha de um conjunto de testes contém um número inteiro N (1 <= N <= 1000) que indica o total de alunos na turma. As N linhas seguintes contêm, cada uma, um par de números inteiros C (1 <= C <= 20000) e M (0 <= M <= 100), indicando respectivamente o código e a média de um aluno. O final da entrada é indicado por uma turma com N = 0. Saída Para cada turma da entrada seu programa deve produzir três linhas na saída. A primeira linha deve conter um identificador do conjunto de teste, no formato “Turma n”, onde n é numerado a partir de 1. A segunda linha deve conter os códigos dos alunos que obtiveram a maior média da turma. Os códigos dos alunos devem aparecer na mesma ordem da entrada, e cada um deve ser seguido de um espaço em branco. A terceira linha deve ser deixada em branco. O formato mostrado no exemplo de saída abaixo deve ser seguido rigorosamente. Exemplo Entrada: 3 1 85 2 91 3 73 5 12300 81 12601 99 15023 76 10111 99 212 99 0 Saída: 13 Turma 1 2 Turma 2 12601 10111 212 Restrições 0 <= N <= 1000 (N = 0 apenas para indicar o fim da entrada) 1 <= C <= 20000 0 <= M <= 100 Código em C #include <stdio.h> #define MAX_ALUNOS 1000 int main() { int i, indice_melhor, n; int turma=1; struct { int codigo, media; } alunos[MAX_ALUNOS]; /* le numero de alunos da primeira turma */ scanf("%d", &n); while (n > 0) { /* le dados dos alunos */ for (i = 0; i < n; i++) scanf("%d %d", &alunos[i].codigo, &alunos[i].media); /* procura aluno de maior media */ indice_melhor = 0; for (i = 1; i < n; i++) if (alunos[i].media > alunos[indice_melhor].media) indice_melhor = i; /* escreve resposta */ printf("Turma %d\n%d\n\n", turma++, alunos[indice_melhor].codigo); /* le numero de alunos da proxima turma */ scanf("%d", &n); } return 0; } 14 Código em C++ #include <iostream> const int MAX_ALUNOS = 1000; int main() { int i, indice_melhor, n; int turma=1; struct { int codigo, media; } alunos[MAX_ALUNOS]; // le numero de alunos da primeira turma cin >> n; while (n > 0) { // le dados dos alunos for (i = 0; i < n; i++) cin >> alunos[i].codigo >> alunos[i].media; // procura aluno de maior media indice_melhor = 0; for (i = 1; i < n; i++) if (alunos[i].media > alunos[indice_melhor].media) indice_melhor = i; // escreve resposta cout << "Turma " << turma++ << "\n"; cout << alunos[indice_melhor].codigo << "\n\n"; // le numero de alunos da proxima turma cin >> n; } return 0; } 15 Problema Z: Dobradura de Papel Arquivo: dobradura.[c|cpp|java] Se uma grande folha de papel é dobrada na metade, e então na metade outra vez e assim sucessivamente, com todas as dobras paralelas então, existirá uma série de vincos (marcas de dobra) paralelas. Algumas apontando para cima, outras para baixo, dividindo o papel em fracões do comprimento original. Se o papel for aberto apenas “meio caminho” em cada dobra, então dobra formará um ângulo de 90 graus. Então, (vista pela borda) ela forma uma "curva dragão". Por exemplo, se quatro dobras sucessivas forem feitas a curva a seguir será vista(note que não cruza ela mesma, mas dois cantos se tocam): s Figura 2: Desdobrando o papel Escreva um programa para desenhar a curva que aparece após N dobras. A especificação exata da curva é a seguinte: o papel inicialmente é plano, com a “borda inicial” à esquerda, se olhado de cima. A metade direita é dobrada de forma que cobre a metade esquerda. Então, a metade direita da nova “folha dupla” é dobrado sobre a metade esquerda, para formar uma folha de 4 camadas, e assim por diante, até N dobraduras. Então, cada dobra é aberta de uma dobra de 180 graus para uma dobra de 90 graus. Finalmente o papel é olhado pela borda para vermos a “curva dragão". Nesta vista, a única parte não modificada da folha original é o pedaço contendo a “borda inicial” e esta parte está na horizontal, com a “borda inicial” na esquerda. Isto define a curva de maneira única. Na figura acima, a “borda inicial” é a terminação esquerda da parte horizontal da curva no canto inferior direito(marcada com o ’s’ de Start em Inglês). A partes horizontais deverão ser mostradas com caractere sublinhado( “_” ), e as partes verticais deverão ser mostradas com o caráter “|”. O arquivo de entrada consistirá de uma série de linhas, cada uma com um único número N (1 ≤ N ≤ 13). O final das entradas será marcado por uma linha contendo um Zero. O arquivo de saída consistirá de uma série de “curvas dragão", uma para cada valor de N na entrada. Sua figura deve estar deslocada o mais a esquerda e acima possível. Note que para N grandes, a figura terá mais de 80 caracteres de largura, o que parecerá confuso na tela. O padrão gerado para cada número diferente de dobraduras terminará com um caractere ‘ˆ’. Entradas 2 4 1 0 Saídas |_ _| ^ _ _ |_|_| |_ _| _| |_| ^ _| ^ 16