UVa: Começando com Problemas de Torneio de Programação – Problema 3n + 1

24/02/2011 | By | 8 Comments

Tempos atrás perguntei no twitter se o pessoal estaria interessado em artigos/tutoriais sobre problemas torneio de programação. Mas não no sentido de dicas para torneios, e sim focando nos algoritmos.

logouva UVa: Começando com Problemas de Torneio de Programação   Problema 3n + 1

publiquei aqui no blog uma página com alguns problemas do UVa Online Judge que resolvi em Java. E esse problemas são ótimos para melhorar a lógica de programação, além da oportunidade de aprender mais algoritmos. E isso é super importante para a nossa carreira, pois não fazemos aplicações que requerem apenas trabalho braçal, mas sim intelectual.

O UVa Online Judge é um dos juízes online mais utilizados, e tem dezenas de problemas para serem resolvidos, desde problemas fáceis à problemas difíceis.

Alguns algoritmos que são usados para resolver esses problemas: adhoc (simulação), ordenação e busca, grafos, teoria matemática, etc. Esses algoritmos também são legais para ter uma idéia de como podem ser usados num contexto mais ou menos real, já que na faculdade a gente aprende a fazer algoritmo de grafos, mas geralmente não estão contextualizados.

Aqui no blog, vou focar em Java. A linguagem mais apropriada para torneios é C, C++, mas aqui faço por hobby.

Vamos então começar com o problema mais clássico, que é o primeiro a ser resolvido que é o número 100: 3n + 1.

Link do problema no UVa aqui.

Este problema também é conhecido como Conjectura de Collatz e nunca foi resolvido.

O problema consiste no seguinte:

  • Se o número é par, então divida por dois.
  • Se o número é ímpar, então multiplique por três e some por um.

3nplus1 UVa: Começando com Problemas de Torneio de Programação   Problema 3n + 1

O problema no Uva pede para contar o número de m-ciclos em um determinado intervalo de inteiros n, m.

Vamos então ao código:

package com.loiane.uva;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * Problem 100 - The 3n + 1 problem
 * 
 * Problem Link:
 * http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=3&page=show_problem&problem=36
 * 
 * Run time: 0.208s
 * 
 * @author Loiane Groner
 * http://loiane.com
 * http://loianegroner.com
 */
public class Main {
	
	static int[] cache = new int[1000001];

	public static void main(String[] args) throws IOException {
		
		BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
		String s;
		long i, j;
		String[] tokens;
		final String regexWhitespace = "\\s+";
		final String whiteSpace = " ";
		
		while ((s = bf.readLine()) != null){
			s = s.trim().replaceAll(regexWhitespace, whiteSpace);
			tokens = s.trim().split(whiteSpace);
			i = Long.parseLong(tokens[0]);
			j = Long.parseLong(tokens[1]);
			
			System.out.println(i + whiteSpace + j + whiteSpace + countCycle(i,j));
		}
	}
	
	static int countCycle (long n, long m){
		long i, j;
		int max = 0;
		int aux;
		
		if (n > m){
			i = m;
			j = n;
		} else{
			i = n;
			j = m;
		}
		
		for (long k=i; k<=j; k++){
			aux = collatz(k);
			if (max < aux){
				max = aux;
			}
		}
		
		return max;
	}
	
	static int collatz(long n){
		
		long index = n;
		
		if (cache[(int) n] != 0){
			return cache[(int) n];
		}
		
		int count = 1;
		while (n > 1){
			if ((n % 2) == 0){
				n /= 2;
			} else{
				n = (n*3)+1;
			}
			count++;
		}
		cache[(int) index] = count;
		return count;
	}

}
  • O problema consiste na leitura de dois números inteiros: i e j por linha. Não temos um número exato de linhas, por isso lemos até acabar, ou seja, a entrada for nula.
  • Uma dica para leitura de números: BufferedReader + Long.parseLong() é mais rápido do que Scanner.
  • Fazemos trim e eliminamos todos os espaços da linha pois não sabemos se pode vir algum “lixo”.
  • No método countCycle verificamos qual número é maior (i ou j) para fazermos o passe no loop (pode vir com a ordem trocada, não sabemos).
  • O método collatz faz o cálculo que queremos.
  • Usamos um cache de tamanho 1.000.000, pois isso vai nos ajudar a ganhar tempo. Por exemplo, suponha que tenha uma entrada 1 100, então vamos calcular esse período e guardar no cache. Depois temos uma entrada 1 200, ou seja, podemos usar o que já calculamos antes e calcular apenas o período novo (101 a 200).
  • O limite de run time desse problema é de 3s. O algoritmo acima foi executado em 0.208 (o que é um tempo bom para Java).
  • Outra dica: toda classe submetida para o UVa em Java deve ter o nome Main, isso é padrão. Se tentar submeter com outro nome, não vai funcionar. O arquivo também não pode conter nenhum comentário. Também não podem pertencer à nenhuma pacote, tem que ser default.

Testando o input e output:

package com.loiane.uva;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

/**
 * Test Case
 * Problem 100 - The 3n + 1 problem
 * 
 * @author Loiane Groner
 * http://loiane.com
 * http://loianegroner.com
 */
public class TestProblem100 {

	@Test
	public void testProblem100(){
		
		assertEquals(20, Main.countCycle(1, 10));
		assertEquals(125, Main.countCycle(100, 200));
		assertEquals(89, Main.countCycle(201, 210));
		assertEquals(174, Main.countCycle(900, 1000));
	}
}

É isso pessoal! Conto com o feedback de vocês para saber se querem que continue com essa série.

Em cada problema podemos mostrar um algoritmo novo! Esses algoritmos também são ótimos para treinar TDD. icon smile UVa: Começando com Problemas de Torneio de Programação   Problema 3n + 1

Bons códigos!

Filed in: UVa Online Judge | Tags: , , , , ,

Comments (8)

  1. Oi Loiane! Gostei muito do seu post! Engraçado q apenas alguns dias atrás eu tava dando uma geral no seu blog e pensei com meus botões: “Seria legal ela dar umas pisadas em problemas de lógica/matemática”. Agora foi =]. Esses problemas são muito bons mesmo pra treinar TDD e, de quebra, a gente sempre aprende algo novo. Parabéns!

  2. raoni

    eu não entendi muito bem esta afirmação: “Este problema também é conhecido como Conjectura de Collatz e nunca foi resolvido.”
    o que você quer dizer com isso? o problema 3n+1 nunca foi resolvido?
    mas, então, o que você fez?
    ah… acho que você quis dizer que a conjetura não foi resolvidA, ou melhor, provada? mas isso já não é a definição de conjectura?
    isso me deixou confuso.

  3. Gostei do exercício.

    Realizei o exercício com outra linguagem: C

    Abraços

  4. Luis

    Olá ! Muito bom, estava tentando fazer esse problema mas o UVa nao aceitava de jeito nenhum, talvez o problema foi eu não usado regex para tratar os dados de entrada. Voce conhece outros blogs que fornecem auxilio semelhante usando java (pt/en) para competições de programação ? Obrigado.

    • Oi Luis,
      Os sites de apoio que uso são os que a própria Universidade de Valladolid indicam.
      Mas possuem apenas dicas de como resolver o problema, não tem o código exposto.

      Site em java é mais difícil de encontrar pois a linguagem considerada como melhor opção para essas competições é C/C++.
      Java peca um pouco na performance e consumo de memória nesse caso.

  5. Mário Henrique

    ótima matéria, sempre bom saber uns truques novos em Java. valeu!

Leave a Reply

Trackback URL | RSS Feed for This Entry

VideoPokiesOnline.com is the leading Pokies - Online Casino Guide in Australia. Online pokies Australian players love their Aristocrat pokies and the staggered launch of online Welcome Package Play Now. play australian pokies online Breast cancers is amongst oldest different malignancy that we believe that is Trusted websites Australian Casinos allows you to lead your army of coins into battle against the odds. Free Online Pokies at Top Rated Australian Online Casinos.
Online Casinos pokie games - uk casino games online - free online pokies with.
Slots and enjoy: ?one of a kind VIP program ? $500 Welcome Package ? Online Pokies Australia online casinos and land parlors. Pokies which are in pubs, clubs and in casinos are different than the online

Online Slots Wild Jack.