Mooshak #01 - Introdução
(semana de 08/11 a 12/11)
Nota Inicial
Os exercício do Mooshak desta aula não contam para nota e são completamente opcionais (a vossa prioridade deve ser primeiro completar os exercícios base das aulas práticas). Os exercícios aqui colocados destinam-se a quem quer ir mais além do que requisitos mínimos e quiser ter uma camada de submissão com avaliação automática, sendo que todas as semanas iremos colocar disponíveis novos problemas.
Para tornar tudo um pouco mais interessante, eu (Pedro Ribeiro) deixo desde já prometido que irei pagar uma refeição na minha companhia (uma francesinha no Capa Negra II) a três estudantes desta UC:
Os 2 estudantes com mais problemas corretamente submetidos no final do semestre (sob um código de conduta de não tentarem simplesmente "copiar código").
Um outro estudante que se tenha destacado nesta componente, segundo a minha avaliação (ex: resolveu os problemas mais difíceis, teve o código mais criativo, etc).
Espero para ver os vosses "dotes" algorítmicos ao longo destas semanas! :)
Problemas para submissão
Nesta aula foram disponibilizados os seguintes problemas:
O Mooshak estará sempre em "modo IOI" (de pontos), ou seja, cada teste vale um determinado conjunto de pontos e apenas quando se tem 100 se acertou completamente no problema.
Para aceder ao sistema use o seu login (com "up")
e a password que lhe foi enviada para o email institucional (email enviado a 8 Nov com o título "[AED] Password para o Mooshak - login") (se tiver problemas em aceder envie uma mensagem no Slack ao docente Pedro Ribeiro)
Leia o enunciado do problema [AED 01] O sentido da vida (que é trivial)
Familiarize-se com as secções típicas de um enunciado no Mooshak de AED (e de um problema num online judge, de um modo geral):
Uma introdução no início com motivação e contexto
Secção Problema descreve resumidamente o problema e as variáveis envolvidas
Seccão Input descreve em detalhe como é dado o input (que deve ser sempre lido do stdin)
Seccão Output descreve em detalhe como deve ser escrito o output (que deve ser sempre escrito para o stdout, sendo que todas as linhas devem terminar com o caracter de mudança de linha)
Secção Restrições descreve os limites de todas as variáveis envolvidas (é garantido que os testes respeitam e não precisa de verificar no código; o intuito desta secção é ajudar a perceber a complexidade necessária)
Pelo menos um exemplo de input e output, tipicamente com uma secção que o explica.
Algumas informações técnicas:
É esperado que submeta um único ficheiro de código em C++ com extensão .cpp. Se usar mais do que uma classe, pode simplesmente colocar tudo no mesmo ficheiro.
Em todos os problemas a leitura é feita a partir da entrada padrão (stdin) e a escrita é feita para a saída padrão (stdout).
Todas as linhas do input e do output devem terminar com o caracter de mudança de linha (mesmo a última).
Para iniciar a sua "viagem", aqui fica um exemplo de solução para este problema: aed01.cpp
Deve começar por compilar o seu programa na sua máquina (o Mooshak não é para ser usado como um compilador!). Para saber o comando exacto com que o seu programa será compilado, carregue no botão help.
Espreite tudo o que está disponível na página de ajuda: não apenas os comandos de compilação, mas também as versões do compiladores, os limites (memória, tempo, tamanho do código) e o que significa cada um dos resultados possíveis.
Se quiser usar o CLion pode fazer "File > New Project > C++ Executable", escolher um nome (ex: aed01) e depois programar em main.cpp (neste caso por exemplo copiar o código dado anteriormente).
Ao executar o seu programa tem por exemplo duas maneiras de o testar com um dado input:
Interativamente: ao executar o programa fica parado à espera de input e pode simplesmente escrever (ou colar o input que copiou de outro sítio, como por exemplo o input de exemplo de enunciado) [no CLion ao executar a shell em baixo fica à espera do seu input]
Pode colocar o input num ficheiro (ex:aed01.txt) e fazer redirecionamento de input (executavel < aed01.txt). Se estiver numa shell de Linux, pode até compilar e executar num mesmo comando. Por exemplo:
g++ -o aed01 aed01.cpp && ./aed01 < aed01.txt
Depois de ter testado na sua máquina, submeta então o código no Mooshak para o problema [AED 01] O sentido da vida
Para ficar familiarizado com os erros e confortável com a maneira como o Mooshak funciona, o objectivo deste exercício é provocar alguns erros ao submeter o problema [AED 01] O sentido da vida. Use como base o seu código aceite.
Provoque um erro de apresentação (Presentation Error) (ex: retire a mudança de linha na impressão) e submeta para ver o feedback detalhado que é dado nesse caso.
Provoque um erro de compilação (Compile Time Error) (ex: retirar um ';') e verifique o feedback detalhado dado nesse caso.
Provoque uma resposta errada (Wrong Answer) (ex: mude a impressão para ser sempre 3). Note no feedback detalhado como consegue ver agora em que testes falha, e como tem acesso ao primeiro teste onde falha (sendo nós controlamos os testes que ficam "disponíveis": tipicamente o último é sempre secreto para evitar que façam "reverse engineering" a todos os testes e manter-vos "honestos").
Provoque um excesso de tempo de execução (Time Limit Exceeded) (ex: faça com que o ciclo nunca termine) e verifique qual o feedback detalhado (cada problema pode ter um tempo limite diferente: por exemplo este [AED 01] tem configurado 1 segundo como tempo limite de execução)
Como isto já deve ficar com uma ideia de alguns dos princiais erros, e do comportamento do Mooshak nesses casos. Lidar com isto no futuro será um skill importante, não apenas neste unidade curricular.
Exercício 3) Resolvendo um problema
Agora que já percebeu a ideia, passemos para um primeiro problema um pouco mais "a sério". Estes problema envolve apenas instruções básicas como ciclos:
Resolva e submeta o problema [AED 02] Números arranjadinhos
Pode optar por tentar resolver completamente de forma autónoma, ou consultar dicas, que estão "escondidas" para não serem spoilers para todos (mesmo que faça "sozinho", não deixe no final de vir espreitar as dicas).
Os limites são pequenos e por isso é exequível fazer um ciclo a começar em Ni e ir iterando sobre todos os inteiros consecutivos até chegar a um cujos dígitos tenham soma Ki. (consegue estimar a complexidade? e se os limites fossem maiores isto chegaria?)
Faça uma função separada para receber um inteiro e devolver a soma dos seus dígitos, para o código ficar minimamente organizado.
Para obter a soma dos dígitos, pode por exemplo fazer um ciclo onde vai repetidamente extraindo o resto da divisão por 10 (instrução '%') para saber o último dígito, seguido de uma divisão por 10 para retirar esse mesmo dígito.
Exercício 4) Dificuldade++
Para terminar esta primeira aula, aqui fica um problema um pouco mais "giro" para que possam usar um pouco a cabeça a pensar num algoritmo, ao invés de ser logo "imediata" uma ideia de solução.
Era mais fácil se em vez de matrículas fosse só comparar números não? Porque não converter então a matrícula num número?
Para converter pensem na matrícula como um número
escrito numa "base" diferente e na maneira como convertem
um qualquer base para decimal. Por exemplo, se a matrícula
fosse apenas XN1N2, o seu número de
ordem era igual a
valor(X)*100+N1*10+N2
Cuidado com as letras 'K', 'W' e 'Y' que não devem ser
consideradas
Quando estamos numa dada geração, com avançar todas as matrículas anteriores? Por exemplo, a matrícula 00-00-AA não é a primeira, mas sim qual?
Se tiverem mais dúvidas podem e devem usar o Slack (usando por exemplo o canal #mooshak ou enviando mensagem directa ao docente Pedro Ribeiro).
Exercício de Desafio
Todas as semanas vou colocar disponível pelo menos mais um exercício um pouco mais desafiante.
Para esta semana o desafio tem a ver com a eficiência algorítmica e como desenhar um algoritmo mais eficiente para um problema que já deve ter resolvido. Para isso, deve tentar resolver o seguinte problema, que está disponível para submissão no Mooshak:
Notem a diferença nas restrições e como os limites impedem uma solução naive que itere sobre todos os inteiros consecutivos até descobrir a resposta.
Como este é um problema de desafio, não vou para já dar nenhuma dica, ficando à espera de ver os vossos programas :)
Se já tiverem feito tudo e estiverem "presos" neste, e quiserem mesmo fazer o desafio, podem contactar-me para eu "dosear" as dicas, sabendo que este problema é substancialmente mais difícil que a versão "fácil" original.