Skip to Content

Entrada y salida

Recursos
FuenteRecursoNotas
IUSACO2.1 - Input and Output

este módulo se basa en esto

CPH1.2 - Input and Output

cin, getline, archivos

PAPS12.3 - Input and Output

cin, getline

Recursos
FuenteRecursoNotas
IUSACO2.1 - Input and Output

este módulo se basa en esto

Los fragmentos de código de abajo leen tres enteros en una sola línea e imprimen su suma. Por ejemplo, dada la entrada

1 2 3

la salida será la siguiente:

The sum of these three numbers is 6

Se pueden probar en ide.usaco.guide .

E/S estándar

En la mayoría de los sitios (como Codeforces y CSES), y en los problemas de USACO posteriores a diciembre de 2020, la entrada y la salida son estándar.

Método 1 - <iostream>

Más directo de usar. Llamar al operador de extracción operator>> sobre cin lee datos separados por espacios en blanco desde la entrada estándar. De forma similar, llamar al operador de inserción operator<< sobre cout escribe en la salida estándar. La secuencia de escape  \n representa un salto de línea.

#include <iostream> using namespace std; int main() { int a; int b; int c; cin >> a >> b >> c; // "\n" también se puede reemplazar por endl cout << "The sum of these three numbers is " << a + b + c << "\n"; }

Método 2 - <cstdio>

Esta biblioteca incluye las funciones scanf y printf, que son un poco más complicadas de usar.

#include <cstdio> using namespace std; int main() { int a; int b; int c; /* * %d indica que se está leyendo un valor de tipo int. * Para leer un número de 64 bits (long long), * usar %lld (algunos OJs pueden necesitar %I64). * Hay muchos otros especificadores; ver el enlace para más detalles. * * Hay que agregar un carácter & (operador de dirección) al usar * scanf, SALVO que se esté leyendo un string con %s. * * Se pueden leer varios valores a la vez, como se muestra abajo. */ scanf("%d %d %d", &a, &b, &c); /* * Los especificadores de printf son en su mayoría los mismos que los de * scanf, con la excepción notable de los números de punto flotante. * Usar una barra invertida seguida de la letra n * en minúscula para denotar un salto de línea. * El operador de dirección (&) no se usa aquí. */ printf("The sum of these three numbers is %d\n", a + b + c); }

Método 1 - Scanner y System.out.print

En las clases de CS, probablemente se haya implementado la entrada y la salida usando entrada estándar y salida estándar, o usando Scanner para leer la entrada y System.out.print para imprimir la salida.

import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int a = sc.nextInt(); int b = sc.nextInt(); int c = sc.nextInt(); System.out.print("The sum of these three numbers is "); System.out.println(a + b + c); } }

Esto funciona, pero Scanner y System.out.print son lentos cuando hay que manejar la entrada y la salida de decenas de miles de líneas.

Método 2 - BufferedReader y PrintWriter

Son más rápidos porque bufferizan la entrada y la salida y las manejan todas de una vez, en lugar de parsear cada línea por separado. Sin embargo, BufferedReader es más difícil de usar que Scanner. Tiene bastantes más métodos y hay que importar la biblioteca io para usarlo. Un StringTokenizer se usa para partir la línea de entrada por espacios en blanco en tokens, a los que luego se accede de a uno con el método nextToken().

import java.io.*; import java.util.StringTokenizer; public class Main { public static void main(String[] args) throws IOException { BufferedReader r = new BufferedReader(new InputStreamReader(System.in)); PrintWriter pw = new PrintWriter(System.out); StringTokenizer st = new StringTokenizer(r.readLine()); int a = Integer.parseInt(st.nextToken()); int b = Integer.parseInt(st.nextToken()); int c = Integer.parseInt(st.nextToken()); pw.print("The sum of these three numbers is "); pw.println(a + b + c); /* * Hay que incluir la línea de abajo, ya que * hace flush y cierra el flujo de salida. */ pw.close(); } }

Método 3 - Plantilla de E/S

La siguiente plantilla (una versión acortada de Kattio.java de Kattis) envuelve BufferedReader y PrintWriter y se encarga del procesamiento de strings. Puede resultar más cómoda que el método 2, o no.

import java.io.*; import java.util.*; /** * Rutinas de E/S simples y moderadamente rápidas. * Algunas notas: * * - Al terminar, siempre hay que hacer io.close() o io.flush() sobre la * instancia de Kattio; si no, se puede perder salida. * * - Los métodos nextInt(), nextDouble() y nextLong() lanzan una * excepción si no queda más dato en la entrada. * * @author: Kattis */ class Kattio extends PrintWriter { private BufferedReader r; private StringTokenizer st; // entrada estándar public Kattio() { this(System.in, System.out); } public Kattio(InputStream i, OutputStream o) { super(o); r = new BufferedReader(new InputStreamReader(i)); } // entrada por archivo al estilo USACO public Kattio(String problemName) throws IOException { super(problemName + ".out"); r = new BufferedReader(new FileReader(problemName + ".in")); } // devuelve null si no hay más entrada public String next() { try { while (st == null || !st.hasMoreTokens()) st = new StringTokenizer(r.readLine()); return st.nextToken(); } catch (Exception e) {} return null; } public int nextInt() { return Integer.parseInt(next()); } public double nextDouble() { return Double.parseDouble(next()); } public long nextLong() { return Long.parseLong(next()); } } public class Main { public static void main(String[] args) { Kattio io = new Kattio(); int a = io.nextInt(); int b = io.nextInt(); int c = io.nextInt(); io.print("The sum of these three numbers is "); io.println(a + b + c); /* * Hay que incluir la línea de abajo, ya que * hace flush y cierra el flujo de salida. */ io.close(); } }
extends

extends se usa para que Kattio herede métodos de PrintWriter (incluidos print(), println() y close()). Si interesa, ver aquí  para más detalles.

Los métodos de entrada de nuestra clase Kattio imitan a los de Scanner. Dada una instancia io:

MétodoDescripción
io.next()Lee el siguiente token (hasta un espacio en blanco) y devuelve un String
io.nextInt()Lee el siguiente token (hasta un espacio en blanco) y lo devuelve como int
io.nextLong()Lee el siguiente token (hasta un espacio en blanco) y lo devuelve como long
io.nextDouble()Lee el siguiente token (hasta un espacio en blanco) y lo devuelve como double
io.print(arg)Imprime arg en el flujo de salida designado
io.println(arg)Imprime arg en el flujo de salida designado y agrega un salto de línea
io.close()Cierra el flujo de salida y hace flush de la salida. Hay que llamar a esto (o a io.flush()) al final, o no se verá ninguna salida!

Método 1 - input() y print()

La forma más intuitiva de hacer entrada/salida es usar los métodos incorporados input() y print(). El método input() devuelve la siguiente línea, y se puede procesar con varios métodos de Python. El método print() recibe un string y un string opcional end (por defecto '\n'). Abajo hay una demostración anotada de distintos escenarios de entrada/salida.

# Leer un string my_str = input() # Imprime el string en su propia línea print(my_str) # Leer un entero n en una sola línea n = int(input()) # Imprime n con " test" (sin salto de línea) después print(n, end=" test")

Método 2 - stdin y stdout

El primer método de lectura de entrada puede ser mucho más lento (a veces cientos de veces más lento!) que usar stdin. Combinado con la velocidad de ejecución relativamente lenta de Python, leer la entrada rápido se vuelve increíblemente importante.

# Importar el módulo sys para usar stdin/stdout import sys # sys.stdin/stdout es similar a un archivo: leemos líneas para entrada/salida my_str = sys.stdin.readline() sys.stdout.write(str(myStr) + "\n") # Renombrar los métodos read/write por conveniencia input = sys.stdin.readline print = sys.stdout.write # Leer un entero como entrada my_int = int(input()) # sys.stdout.write exige formatear el código a mano print(str(my_int) + "\n") """ Para entradas más grandes, se puede bufferizar la entrada del problema y recorrerla uno mismo. Este es el método de entrada más rápido en Python. """ all_data = sys.stdin.read().split("\n")

También se puede usar split, map o una comprensión de listas  para leer varios enteros separados por espacios en blanco en la misma línea.

import sys # Leer una serie de números en una línea a una lista nums = [int(x) for x in input().split()] # Esto hace lo mismo nums = list(map(int, input().split())) # stdin/stdout: reemplazar input() por sys.stdin.readline() nums = list(map(int, sys.stdin.readline().split()))

Se puede usar algo similar a lo de arriba si se desempaquetan una cantidad fija de enteros.

import sys # Leer los enteros n y m en la misma línea con una comprensión de listas n, m = [int(x) for x in input().split()] # Lo mismo pero con map n, m = map(int, input().split()) # stdin y stdout n, m = map(int, sys.stdin.readline().split())

Así, leer tres enteros e imprimir su suma es bastante simple. A mayor escala (miles de enteros), usar stdin y stdout se vuelve mucho más importante por la velocidad:

import sys a, b, c = map(int, input().split()) print("The sum of these three numbers is", a + b + c) # stdin y stdout a, b, c = map(int, sys.stdin.readline().split()) print("The sum of these three numbers is", a + b + c)

Problema de ejemplo - Weird Algorithm

HechoFuenteNombreDificultadTagsSolución
CSESWeird AlgorithmNormal

¡Intentar implementarlo!

Recursos
FuenteRecursoNotas
GCP1.3 - CSES Problem Set

solución de ejemplo en C++ para este problema

Solución - Weird Algorithm

#include <iostream> using namespace std; int main() { long long x; cin >> x; while (x != 1) { cout << x << " "; if (x % 2 == 0) { x /= 2; } else { x = 3 * x + 1; } } cout << x << endl; }

Método 1 - Scanner y System.out.print

import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner r = new Scanner(System.in); long x = r.nextLong(); while (x != 1) { System.out.print(x + " "); if (x % 2 == 0) { x /= 2; } else { x = 3 * x + 1; } } System.out.println(x); } }

Método 2 - BufferedReader y PrintWriter

import java.io.*; public class Main { public static void main(String[] args) throws IOException { BufferedReader r = new BufferedReader(new InputStreamReader(System.in)); PrintWriter pw = new PrintWriter(System.out); long x = Long.parseLong(r.readLine()); while (x != 1) { pw.print(x + " "); if (x % 2 == 0) { x /= 2; } else { x = 3 * x + 1; } } pw.println(x); /* * Hay que incluir la línea de abajo, ya que * hace flush y cierra el flujo de salida. */ pw.close(); } }

Con Kattio

import java.io.*; import java.util.*; public class Main { public static void main(String[] args) { Kattio io = new Kattio(); long x = io.nextLong(); while (x != 1) { io.print(x + " "); if (x % 2 == 0) { x /= 2; } else { x = 3 * x + 1; } } io.println(x); /* * Hay que incluir la línea de abajo, ya que * hace flush y cierra el flujo de salida. */ io.close(); } // CodeSnip{Kattio} }
x = int(input()) while x != 1: print(x, end=" ") if x % 2 == 0: x //= 2 else: x = 3 * x + 1 print(x)

Como se indica en el recurso de arriba, este problema requiere enteros de 64 bits. La siguiente solución, que usa int en lugar de long, no pasa todos los casos de prueba.

import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner r = new Scanner(System.in); int x = r.nextInt(); while (x != 1) { System.out.print(x + " "); if (x % 2 == 0) { x /= 2; } else { x = 3 * x + 1; } } System.out.println(x); } }

Esto ocurre porque algunos números de la secuencia pueden superar el valor máximo posible del tipo de dato int (23112^{31}-1, como se menciona en el módulo prerrequisito).

Cómo enviar la solución

Hacer lo siguiente para enviar en CSES. Enviar en otras plataformas (como USACO) es similar.

  1. Ejecutar el código de la solución con la entrada de ejemplo y asegurarse de que produce la salida de ejemplo.para problemas con una sola salida correcta
  2. Descargar el código de la solución a un archivo. La extensión debería ser una de .cpp, .java, .py o equivalentes, según el lenguaje de programación.
  3. Abrir el enunciado del problema. Iniciar sesión si no se está ya logueado.
  4. Pulsar la pestaña de envío (en USACO, scrollear hasta el final de la página).
  5. Subir el archivo de la solución. En CSES, si el archivo tenía la extensión correcta, el lenguaje se detecta automáticamente (en USACO, hay que seleccionar el lenguaje). Algunas plataformas (como Codeforces) permiten pegar el código en un cuadro de texto en lugar de subir un archivo.
  6. Enviar la solución. En CSES, se redirige a la página de resultados (en USACO, los resultados aparecen arriba de la página). Si la solución es correcta en todos los casos de prueba, ¡listo! Si no, corregir el código y empezar de nuevo desde el paso 1.

E/S por archivos

En los problemas más viejos de USACO, se dan los nombres de los archivos de entrada y salida y siguen la convención problemname.in. Después de ejecutar el programa, la salida debe imprimirse en un archivo llamado problemname.out.

HechoFuenteNombreDificultadTagsSolución
BronzeFence PaintingNormalSolución

Hay que usar los nombres de archivo correctos al abrir los archivos .in y .out, según el problema. Los nombres de archivo se dan en los problemas de USACO que requieren abrir archivos. Por ejemplo, en el problema de arriba se abrirían paint.in y paint.out.

Método 1 - freopen

Hace falta la biblioteca <cstdio>. Las sentencias freopen reutilizan la E/S estándar para E/S por archivos. Después, se puede usar simplemente cin y cout (o scanf y printf) para leer y escribir datos.

#include <cstdio> #include <iostream> using namespace std; int main() { freopen("problemname.in", "r", stdin); // la siguiente línea crea/sobrescribe el archivo de salida freopen("problemname.out", "w", stdout); // cin ahora lee del archivo de entrada en lugar de la entrada estándar int a; int b; int c; cin >> a >> b >> c; // cout ahora imprime en el archivo de salida en lugar de la salida estándar cout << "The sum of these three numbers is " << a + b + c << "\n"; }

Para probar la solución en local sin E/S por archivos, basta con comentar las líneas con freopen.

Por conveniencia, se puede definir una función que redirija stdin y stdout según el nombre del problema:

#include <cstdio> #include <iostream> using namespace std; // el argumento es el nombre del archivo de entrada sin la extensión void setIO(string s) { freopen((s + ".in").c_str(), "r", stdin); freopen((s + ".out").c_str(), "w", stdout); } int main() { setIO("problemname"); int a; int b; int c; cin >> a >> b >> c; cout << "The sum of these three numbers is " << a + b + c << "\n"; }

Método 2 - <fstream>

Con este método no se puede usar E/S al estilo C (scanf, printf).

#include <fstream> using namespace std; int main() { ifstream fin("problemname.in"); ofstream fout("problemname.out"); int a; int b; int c; fin >> a >> b >> c; fout << "The sum of these three numbers is " << a + b + c << "\n"; }

Java

De nuevo, hay que usar BufferedReader y PrintWriter. Nótese que la inicialización static de r y pw es un poco distinta.

import java.io.*; import java.util.StringTokenizer; public class Main { public static void main(String[] args) throws IOException { BufferedReader r = new BufferedReader(new FileReader("problemname.in")); PrintWriter pw = new PrintWriter("problemname.out"); StringTokenizer st = new StringTokenizer(r.readLine()); int a = Integer.parseInt(st.nextToken()); int b = Integer.parseInt(st.nextToken()); int c = Integer.parseInt(st.nextToken()); pw.print("The sum of these three numbers is "); pw.println(a + b + c); /* * Hay que incluir la línea de abajo, ya que * hace flush y cierra el flujo de salida. */ pw.close(); } }

Con Kattio

import java.io.*; import java.util.*; public class Main { public static void main(String[] args) throws IOException { Kattio io = new Kattio("problemname"); int a = io.nextInt(); int b = io.nextInt(); int c = io.nextInt(); io.print("The sum of these three numbers is "); io.println(a + b + c); /* * Hay que incluir la línea de abajo, ya que * hace flush y cierra el flujo de salida. */ io.close(); } // CodeSnip{Kattio} }

Python

Ver aquí  la documentación sobre E/S por archivos.

La forma más intuitiva de hacer E/S por archivos en Python es redirigir la entrada y la salida del sistema a archivos. Después de eso, se pueden usar los métodos input() y print() de arriba como de costumbre.

import sys sys.stdin = open("problemname.in", "r") sys.stdout = open("problemname.out", "w")

Otro enfoque de E/S por archivos en Python es seguir usando el método open(), pero con las funciones incorporadas .readline() o .readlines():

""" Nota: El segundo argumento se puede omitir en el comando open() para archivos de solo lectura """ fin = open("problemname.in", "r") fout = open("problemname.out", "w") # Una forma de leer el archivo usando .readline() line1 = fin.readline() # readline() continúa desde donde se dejó line2 = fin.readline() line3 = fin.readline() # Otra forma es usar un for y .readlines() line_list = [] for line in fin.readlines(): pass # Procesar la entrada acá # imprimir line_list daría [line1, line2, line3] # Salida: fout.write(output_text) # Escribir en el archivo de salida # f-strings: variable1 = 1 variable2 = 2 example_str = f"Hello {variable1} {variable2} World!" # Imprimir example_str daría Hello 1 2 World!
  • fin.readline() devuelve la siguiente línea como string. Este método es útil en problemas donde solo hay que leer pocas líneas pero igual se necesita mapear cada valor a una variable.

  • fin.readlines() devuelve todo el contenido del archivo como una lista, separado por saltos de línea ("\n"). Combinado con un for, este método da una forma concisa de separar variables en la misma línea de un problema. Hay que tener en cuenta que cada entrada de línea en la lista todavía tendrá un "\n" al final.

  • fout.write(data) escribe la variable data en el archivo. data debe ser un string, y se pueden convertir variables que no lo son con str(my_var). El método write() NO escribe un salto de línea al final. También hay que ejecutar fout.write("\n") si se quiere escribir un salto de línea.

  • Las f-strings se agregaron en Python 3.6 y en general se ven mejor que concatenar (sumar) strings. Para definir una f-string, basta con agregar la letra f justo antes del inicio del string, y cualquier variable o expresión entre llaves ({}) se inserta en el string. Como ejemplo, fout.write(f"{var1} {var2} {var3+var4}") se ve mucho más limpio que fout.write(str(var1)+" "+str(var2)+" "+str(var3+var4))

Después de leer una línea, puede hacer falta procesarla más. Python tiene muchos métodos y funciones de string incorporados:

  • str.strip() quita cualquier espacio en blanco al inicio o al final. Siempre hay que ejecutar este método después de leer una línea, para asegurarse de que no quede espacio extra: line = fin.readline().strip()

  • map(func, iterable) aplica una función (el argumento func) a cada elemento de un iterable (lista) que se le pase. Es útil para convertir una lista de strings en una lista de ints: nums = list(map(int, ["1", "2", "3"])). Nótese que map() devuelve un objeto Map, y hay que convertirlo en una lista con list().

  • str.split(delim) parte el string. Si no se pasa argumento, lo parte por espacios. Es útil si se quiere separar un string de enteros separados por espacios en ints: nums = list(map(int, line.split()))

Solución de ejemplo - Fence Painting

Recursos
FuenteRecursoNotas
USACOTechnical Specifications for Contests

Hay que leer esto.


Para una explicación de las soluciones de abajo, ver el módulo Geometría de rectángulos.

Método 1 - freopen

#include <iostream> #include <vector> using namespace std; int main() { // Usar la entrada estándar para leer de "paint.in" freopen("paint.in", "r", stdin); // Usar la salida estándar para escribir en "paint.out" freopen("paint.out", "w", stdout); vector<bool> cover(100); int a, b, c, d; cin >> a >> b >> c >> d; for (int i = a; i < b; i++) { cover[i] = true; } for (int i = c; i < d; i++) { cover[i] = true; } int ans = 0; for (int i = 0; i < cover.size(); i++) { ans += cover[i]; } cout << ans << endl; }

Método 2 - <fstream>

#include <fstream> #include <vector> using namespace std; int main() { ifstream fin("paint.in"); ofstream fout("paint.out"); vector<bool> cover(100); int a, b, c, d; fin >> a >> b >> c >> d; for (int i = a; i < b; i++) { cover[i] = true; } for (int i = c; i < d; i++) { cover[i] = true; } int ans = 0; for (int i = 0; i < cover.size(); i++) { ans += cover[i]; } fout << ans << endl; }

Método 1 - Scanner y PrintWriter

import java.io.*; import java.util.Scanner; public class Main { public static void main(String[] args) throws IOException { Scanner r = new Scanner(new File("paint.in")); PrintWriter pw = new PrintWriter("paint.out"); int a = r.nextInt(); int b = r.nextInt(); int c = r.nextInt(); int d = r.nextInt(); int[] cover = new int[100]; for (int i = a; i < b; i++) { cover[i] = 1; } for (int i = c; i < d; i++) { cover[i] = 1; } int ans = 0; for (int i = 0; i < cover.length; i++) { ans += cover[i]; } pw.println(ans); /* * Hay que incluir la línea de abajo, ya que * hace flush y cierra el flujo de salida. */ pw.close(); } }

Método 2 - BufferedReader y PrintWriter

import java.io.*; import java.util.StringTokenizer; public class Main { public static void main(String[] args) throws IOException { BufferedReader r = new BufferedReader(new FileReader("paint.in")); PrintWriter pw = new PrintWriter("paint.out"); StringTokenizer st = new StringTokenizer(r.readLine()); int a = Integer.parseInt(st.nextToken()); int b = Integer.parseInt(st.nextToken()); st = new StringTokenizer(r.readLine()); int c = Integer.parseInt(st.nextToken()); int d = Integer.parseInt(st.nextToken()); int[] cover = new int[100]; for (int i = a; i < b; i++) { cover[i] = 1; } for (int i = c; i < d; i++) { cover[i] = 1; } int ans = 0; for (int i = 0; i < cover.length; i++) { ans += cover[i]; } pw.println(ans); /* * Hay que incluir la línea de abajo, ya que * hace flush y cierra el flujo de salida. */ pw.close(); } }

Con Kattio

import java.io.*; import java.util.*; public class Main { public static void main(String[] args) throws IOException { Kattio io = new Kattio("paint"); int a = io.nextInt(); int b = io.nextInt(); int c = io.nextInt(); int d = io.nextInt(); int[] cover = new int[100]; for (int i = a; i < b; i++) { cover[i] = 1; } for (int i = c; i < d; i++) { cover[i] = 1; } int ans = 0; for (int i = 0; i < cover.length; i++) { ans += cover[i]; } io.println(ans); /* * Hay que incluir la línea de abajo, ya que * hace flush y cierra el flujo de salida. */ io.close(); } // CodeSnip{Kattio} }

Método 1

with open("paint.in", "r") as inp: lines = [line for line in inp] a, b = map(int, lines[0].split()) c, d = map(int, lines[1].split()) cover = [0] * 100 for i in range(a, b): cover[i] = 1 for i in range(c, d): cover[i] = 1 ans = 0 for i in range(len(cover)): ans += cover[i] with open("paint.out", "w") as out: print(ans, file=out) # out.write(str(ans) + '\n') también funciona

Método 2

Redirigir la entrada por archivo usando sys, como se mencionó arriba.

import sys sys.stdin = open("paint.in", "r") sys.stdout = open("paint.out", "w") a, b = map(int, input().split()) c, d = map(int, input().split()) cover = [0] * 100 for i in range(a, b): cover[i] = 1 for i in range(c, d): cover[i] = 1 ans = 0 for i in range(len(cover)): ans += cover[i] print(ans)

Nota de USACO: espacios en blanco extra

Es importante: USACO agrega automáticamente un salto de línea al final del archivo si no termina con uno.

Hay que asegurarse de no imprimir espacios al final, o se obtendrá un error como el siguiente:

bad

Estos son algunos ejemplos de lo que está permitido y lo que no cuando la salida esperada consiste en un solo entero ans:

C++

cout << ans; // OK, sin salto de línea cout << ans << endl; // OK, salto de línea cout << ans << "\n"; // OK, salto de línea cout << ans << " "; // NOT OK, espacio extra cout << ans << "\n\n"; // NOT OK, salto de línea extra

Java

pw.print(ans); // OK, sin salto de línea pw.println(ans); // OK, salto de línea pw.print(ans + "\n"); // OK, salto de línea pw.print(ans + " "); // NOT OK, espacio extra pw.print(ans + "\n\n"); // NOT OK, salto de línea extra

Python

print(ans, end="") # OK, sin salto de línea print(ans) # OK, salto de línea print(str(ans) + "\n", end="") # OK, salto de línea print(str(ans) + " ", end="") # NOT OK, espacio extra print(str(ans) + "\n") # NOT OK, salto de línea extra