Programação Competitiva

Algoritmo resolvidos e explicados da OBI e Maratona de Programação

  • Clipping de notícias
  • Dicas
    • Atribuição para várias variáveis com o mesmo valor
    • Entrada de vários conjuntos de teste até zeros [linguagem C]
    • Muitas saídas para serem mostradas
    • Saída com testes sequenciais [linguagem C]
    • Otimizações para o código
      • Melhorando o desempenho da entrada e saída [C++]
      • Utilize operadores bitwise
      • Shortcodes
  • Solução Computacional x Matemática
    • Importância de pensar os elementos de uma estrutura for
  • Sobre competições de programação
    • Sobre a maratona de programação
    • Sobre a OBI
    • Links para materiais da maratona
    • Links para materiais da OBI
      • Material introdutório para crianças
        • 1. Bem vindo ao maravilhoso mundo da programação
        • Aprendendo lógica com o Angry Birds
        • Blockly

Melhorando o desempenho da entrada e saída [C++]

Inicialmente foi recomendo utilizar as instruções scanf e printf ao invés de cin e cout, mesmo para a linhagem C++. A questão do desempenho entre essa instruções equivalentes é verdadeira, mas é possível obter o mesmo desempenho com cin/cout do que é obtido com scanf/printf.

ios_base::sync_with_stdio(false);
cin.tie(NULL);

A primeira instrução é um membro estático da função std::ios_base. Ela ativa ou desativa a sincronização dos fluxos no padrão da linguagem C++ com seus fluxos da linguagem C correspondente. Definir sync_with_stdio (false) evita essa sincronização antes das operações de entrada e saída.

A instrução tie() é um método que garante o esvaziamento do cout antes do cin aceitar uma entrada e é importante na utilização do console, que necessita a atualização constante, mas acaba retardando a execução com muitas entradas e saídas (como é o caso da programação competitiva).
Por isso é interessante definir a instrução com um ponteiro NULL.

Agora, especificamente em relação ao cout, embora utilizemos de maneira indiscriminada o cout<<‘\n’ e o cout<<endl para gerar uma nova linha, existe uma diferença no desempenho. A instrução cout<<endl e equivalente à cout<<‘\n’<<flush, e com isso o uso endl é mais lento porque força o fluxo de descarga. Sendo assim, priorize a opção com o \n.

Para um código que faz a leitura de uma grande quantidade de valores e mostra o valor lido imediatamente após sua leitura, o código será o mostrado abaixo, com a inclusão das linhas 7 e 8 e o uso do \n na linha 12. Nada realmente difícil.

#include <iostream> 
using namespace std;
 
int main() {
    int i,cont=0;
 
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);   
 
    do {
        cin >> i;
        cout << i << '\n';
        cont++;
    } while (cont < 999999);
  
    return 0;
}

Para fins de comparação no tempo de execução, preparei dois códigos que podem ser acessados a seguir. Ambos fazem a mesma coisa, mas o primeiro não foi otimizado e leva em torno de 14 vezes mais tempo para executar com a quantidade de entradas colocadas para teste.

  • https://ideone.com/g6l37f (versão não otimizada): executou em 0,01341 segundo
  • https://ideone.com/wy82qv (versão otimizada): executou em 0,000915 segundo

E só para complementar, também fiz uma versão sem a otimização, mas utilizando scanf e printf em C++, e uma versão em linguagem C. Ambas são bem melhores do que a versão não otimizada do código, mas “perdem” para a versão otimizada.

  • https://ideone.com/xsvKCY: executou em 0,001165 segundo
  • https://ideone.com/mE3LpS: executou em 0,001127 segundo
  • Sobre o blog

    Nesse blog estão reunidas explicações preparatórias para a Olimpíada Brasileira de Informática (OBI) e a Maratona de Programação.

    São trazidos problemas e resoluções comentadas.
  • Categorias

    • Competição (34)
      • Maratona de Programação (13)
      • OBI (21)
    • Linguagem (33)
      • C/C++ (32)
      • Python (8)
Proudly powered by WordPress Theme: Parament by Automattic.