블링블링 범블링

[백.단.풀.3] 빠른 A+B (15552) 본문

알고리즘 문제풀이/백준

[백.단.풀.3] 빠른 A+B (15552)

뻠스키 2019. 3. 6. 20:06
Step : <for문 사용해보기>

Title : " 빠른 A+B "


시간 제한메모리 제한제출정답맞은 사람정답 비율
1 초 (하단 참고)512 MB200579790771550.212%

문제

본격적으로 for문 문제를 풀기 전에 주의해야 할 점이 있다. 입출력 방식이 느리면 여러 줄을 입력받거나 출력할 때 시간초과가 날 수 있다는 점이다.

C++을 사용하고 있고 cin/cout을 사용하고자 한다면, cin.tie(NULL)과 sync_with_stdio(false)를 둘 다 적용해 주고, endl 대신 개행문자(\n)를 쓰자. 단, 이렇게 하면 더 이상 scanf/printf/puts/getchar/putchar 등 C의 입출력 방식을 사용하면 안 된다.

Java를 사용하고 있다면, Scanner와 System.out.println 대신 BufferedReader와 BufferedWriter를 사용할 수 있다. BufferedWriter.flush는 맨 마지막에 한 번만 하면 된다.

Python을 사용하고 있다면, input 대신 sys.stdin.readline을 사용할 수 있다. 단, 이때는 맨 끝의 개행문자까지 같이 입력받기 때문에 문자열을 저장하고 싶을 경우 .rstrip()을 추가로 해 주는 것이 좋다.

또한 입력과 출력 스트림은 별개이므로, 테스트케이스를 전부 입력받아서 저장한 뒤 전부 출력할 필요는 없다. 테스트케이스를 하나 받은 뒤 하나 출력해도 된다.

자세한 설명 및 다른 언어의 경우는 이 글에 설명되어 있다.

이 블로그 글에서 BOJ의 기타 여러 가지 팁을 볼 수 있다.

입력

첫 줄에 테스트케이스의 개수 T가 주어진다. T는 최대 1,000,000이다. 다음 T줄에는 각각 두 정수 A와 B가 주어진다. A와 B는 1 이상, 1,000 이하이다.

출력

각 테스트케이스마다 A+B를 한 줄에 하나씩 순서대로 출력한다.

예제 입력 1 

5
1 1
12 34
5 500
40 60
1000 1000

예제 출력 1 

2
46
505
100
2000



이번 문제는 전체적인 언어별 속도 및 문제풀이(Problem Solving = PS) 를 하며, 알아두면 좋은 것들을 소개해놓은 문제이다.

그리고 기본적인 언어 및 컴파일러 별 상식들을 알려주는 문제라고 할 수 있다.


이 문제를 통해 알 수 있는 언어별 상식들을 나열해보자면, (문제의 '블로그' 참조)


C

scanf/printf는 충분히 빠릅니다.

C++

  • 아래 얘기는 cin, cout을 쓸 때의 얘기지, scanf/prinf로 입출력을 하고자 하신다면 그냥 쓰시면 됩니다. scanf/printf는 충분히 빠릅니다.
  • endl은 개행문자를 출력할 뿐만 아니라 출력 버퍼를 비우는 역할까지 합니다. 그래서 출력한 뒤 화면에 바로 보이게 할 수 있는데, 그 버퍼를 비우는 작업이 매우 느립니다. 게다가 온라인 저지에서는 화면에 바로 보여지는 것은 중요하지 않고 무엇이 출력되는가가 중요하기 때문에 버퍼를 그렇게 자주 비울 필요가 없습니다. 그래서 endl을 '\n'으로 바꾸는 것만으로도 굉장한 시간 향상이 나타납니다.
  • cin.tie(NULL)은 cin과 cout의 묶음을 풀어 줍니다. 기본적으로 cin으로 읽을 때 먼저 출력 버퍼를 비우는데, 마찬가지로 온라인 저지에서는 화면에 바로 보여지는 것이 중요하지 않습니다. 입력과 출력을 여러 번 번갈아서 반복해야 하는 경우 필수적입니다.
  • ios_base::sync_with_stdio(false)는 C와 C++의 버퍼를 분리합니다. 이것을 사용하면 cin/cout이 더 이상 stdin/stdout과 맞춰 줄 필요가 없으므로 속도가 빨라집니다. 단, 버퍼가 분리되었으므로 cin과 scanf, gets, getchar 등을 같이 사용하면 안 되고, cout과 printf, puts, putchar 등을 같이 사용하면 안 됩니다.

Java

BufferedWriter 외에도, StringBuilder로 출력을 모아 놓았다가 그 String을 System.out.println하는 방법도 있습니다.

Python

rstrip을 하라는 건 문자열 자체를 변수에 저장하고 싶을 때 얘기지, 개행문자가 맨 끝에 들어와도 int 변환이나 split()을 그대로 할 수 있습니다. 즉 int(sys.stdin.readline()), sys.stdin.readline().split() 이렇게 해도 아무 문제 없습니다. 참고로 이름이 꽤 길기 때문에 저는 input = sys.stdin.readline을 맨 처음에 함으로써 쓰는 편입니다.

Kotlin

Java처럼 BufferedReader와 BufferedWriter를 쓰면 됩니다.

Ruby

gets와 puts는 충분히 빠릅니다.

Go

bufio를 import하면 버퍼를 사용한 빠른 입출력이 가능합니다.

C#

StreamReader로 읽고, StringBuilder로 출력을 모아 놓았다가 그 String을 Console.WriteLine하는 방법이 있습니다. BufferedStream과 StringWriter로 조금 더 향상시킬 수 있는 것 같으나 자세한 것은 다른 분의 답변을 기다리겠습니다.

VB

StringBuilder로 출력을 모아 놓았다가 그 String을 Console.WriteLine하는 방법이 있습니다.

Text

입출력 파일이 예제 포함 2개 이상이기 때문에 Text로는 이 문제를 풀 수 없습니다.

아희

안타깝게도 아희로는 이 문제를 풀 수 없습니다. 입출력하는 방법이 하나뿐인데 시간초과가 납니다.



정도가 있다.

굉장히 얇게 (문제를 풀 때 알아두면 좋은 정도로만) 만 접근했지만, 대충 느낌으로 언어별의 장단점이 와닿을 것이다.
(혹시 와닿지 않으면 댓글로~)


나중에 되서야 알게 되지만, 이런 느낌 혹은 감각 자체가 전체적인 컴퓨팅을 이해하는데 굉장히 큰 도움이 된다.

가끔 문제 풀거나, 개발을 하며 벽에 막혔을 때 이런 상식들이 도움이 될 때가 있는데, 그 때를 위해서 알아두면 좋을 것 같다.


그리고 이 문제를 통해서 또 하나 알 수 있는 것은, 바로 BOJ의 특징 (이라고 쓰고 대다수 알고리즘 문제풀이의 특징, 대회 포함 이라고 읽는다) 을 알려준다는 것이다.

이 또한 발취해오자면,


가장 중요한 팁

  • 채점 데이터에는 예제만 있는 게 아니라 우리에게 공개되지 않는 추가적인 데이터가 많이 준비되어 있습니다. 예제 입출력은 "예를 들어 이런 입력을 줄 것이고 이 때는 이렇게 출력해야 한다"라는 뜻이지, "이게 잘 돌아가면 대충 맞는 코드일 것이다"라는 뜻이 절대 아닙니다!! 그러니 틀렸다고 바로 질문을 올리지 말고 적어도 여러 종류의 입력을 직접 만들어서 넣어 봅시다. 아무렇게나 만들어서 몇 번 넣으면 반례가 나오는 질문이 많이 있습니다.
  • 질문 게시판을 봅시다. 제출한 사람이 많은 문제일 수록 여러분과 똑같은 질문이 들어있을 가능성이 높아집니다.

BOJ 작동 원리

모든 코드를 인공지능이 읽고 채점한다거나, 심지어는 백준님이 읽고 채점하신다고 생각하는 분들이 많은 것 같습니다. 전혀 그렇지 않습니다.

채점 서버에는 여러 쌍의 입력 파일과 출력 파일이 있습니다. (한 쌍일 수도 있습니다.) 코드를 제출하면 그 코드에 입력 파일에 적힌 대로 입력하고 나타나는 출력을 출력 파일과 비교합니다. 모든 입력/출력 파일에 대해 코드가 문제 없이 올바른 출력을 내야 합니다. 여기서 "올바름"이란 것은 단순히 정답과 같은 값이 아니라 같은 출력을 의미합니다. 예를 들어 45.0을 출력해야 하는데 45나 45.00을 출력하면 오답입니다.

스페셜 저지가 있는 문제에는 출력이 올바른지 검사하는 채점 코드가 따로 있습니다. (예를 들어 10^-2 이하의 오차를 허용하는 문제라면 출력과 정답의 오차가 10^-2 이하인지 검사하는 코드가 있습니다.) 그러므로 "올바른 출력"은 여러 가지가 될 수 있고, 그 중 하나만 출력하면 됩니다.

  • 구현을 어떻게 했는지 같은 건 채점 프로그램이 전혀 신경쓰지 않습니다. 그냥 답이 맞게 나오면 됩니다.
  • 줄바꿈이나 띄어쓰기 등을 마음대로 바꿔서 입력받으면 안 됩니다! 예제 형식 그대로 입력받으세요.
  • 줄바꿈이나 띄어쓰기 등을 마음대로 바꿔서 출력해도 안 됩니다! 예제 형식 그대로 출력하세요. 예외적으로, (대부분의 문제에서) 각 줄의 맨 끝에 공백을 넣어도 되고 안 넣어도 되며, 출력의 맨 끝에 줄바꿈을 넣어도 되고 안 넣어도 됩니다.
  • 입력 조건을 코드에 넣을 필요는 없습니다. 예를 들어 "3 <= N <= 5000이다."라고 적혀 있으면 모든 입력 파일이 3 <= N <= 5000의 조건을 지킨다는 뜻이고, if(3 <= N && N <= 5000)을 따로 넣지 않아도 됩니다. 조건을 지키지 않는 파일이 있음을 발견하셨다면 파일이 잘못된 것이므로 게시판에 문제 수정 요청을 쓰면 운영자님이 고쳐 주십니다.
  • 시간 제한은 각 파일마다 따로따로 적용됩니다. 즉 시간 제한이 1초면 첫 번째 파일에 1초, 두 번째 파일에 1초, ..., 마지막 파일에 1초 이내가 걸려야 합니다. 채점 현황에서 볼 수 있는 "시간"은 가장 오래 걸린 파일에서의 구동 시간을 나타냅니다.
  • 메모리 제한도 마찬가지인데, 한 순간에라도 지정된 메모리를 초과하면 안 됩니다. 채점 현황에서 볼 수 있는 "메모리"는 최대 메모리 사용량을 나타냅니다.
  • "첫 줄에 테스트케이스의 개수 T가 주어진다." 또는 "입력은 여러 개의 테스트케이스로 이루어져 있다." 같은 문제는 그 T개의 테스트케이스가 한 파일에 들어있다는 뜻입니다. 그런데 시간과 메모리 제한은 각 파일마다 따로따로 적용된다고 했으므로 주어진 시간 안에 한 파일에 들어있는 모든 테스트케이스가 돌아가야 합니다. 또한 입력과 출력은 분리되어 있으므로 테스트케이스를 받을 때마다 출력해도 되고, 전부 받은 뒤 전부 출력해도 되고, 심지어 받기 전에 출력해도 (???) 됩니다. 하지만 출력 자체의 순서는 지켜야 합니다.
  • 언어에 따라 시간이나 메모리가 초과되고도 정답을 받을 수 있는데, 그 언어가 정해진 시간/메모리 보너스를 받기 때문입니다. https://www.acmicpc.net/help/language
  • 채점 현황의 "컴파일 에러"를 누르면 어디서 에러가 났는지 볼 수 있습니다. 컴파일 에러일 경우에만 가능합니다.

자주 틀리는 요인

너무 많아져서 아래 글로 분리했습니다. https://www.acmicpc.net/blog/view/70

기타 FAQ

Q. 어느 케이스에서 틀렸는지 / 어디서 런타임 에러가 났는지는 볼 수 없나요?

A. 원래 디버깅은 스스로 해야 가장 큰 도움이 됩니다. 그리고 테스트케이스를 볼 수 있게 하면 악용해서 입력과 출력을 짝짓는 것만으로 문제를 통과할 수 있습니다. 그래서 테스트케이스 확인 기능은 없으며, 앞으로도 없을 예정입니다. 런타임 에러 메시지를 볼 수 있게 하면 악용해서 데이터를 얻어낼 수 있으므로 런타임 에러 메시지는 볼 수 없으며, 앞으로도 볼 수 없을 예정입니다.

Q. 파이썬으로 OOOO번을 시간 내에 못 푸나요?

A. 파이썬이 원래 극도로 느리기 때문에 제대로 된 풀이로도 시간초과가 날 수 있습니다. 그 대신 Pypy로 내면 거의 모든 문제를 풀 수 있습니다. (이 글을 쓰고 있는 저는 파이썬과 Pypy만으로 약 2700문제를 풀었습니다.)

Q. 왜 코인 수익이 안 들어오나요?

A. "실수익이 200코인 이상이 되어야 정산이 가능합니다. 접수는 매달 10~15일 사이에 자동으로 진행되며, 정산은 매달 25일에 진행됩니다. 휴일인 경우에는 다가오는 평일에 정산이 진행됩니다." https://www.acmicpc.net/coin/pay

Q. 문제의 정답 비율은 어떻게 계산되나요?

A. https://www.acmicpc.net/problem/15595

Q. 계정 연동에 앳코더는 추가될 수 없나요?

A. 앳코더 API가 없어서 안 된다고 합니다.



가 있다. 물론 모두 같은 방식으로 돌아가는 것은 아니지만, 대다수의 문제 풀이 사이트나 대회들이 이런 방식을 따라가고 있고, Tip 또한 비슷하게 적용된다.

모두 한 번쯤은 정독 후, 참고하면 취업이나 개인적인 문제풀이에 도움이 될 것이다.


사설이 굉장히 길어졌으니, 밑에 이 문제 풀이 코드로 글의 끝을 맺겠다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define _CRT_SECURE_NO_WARNINGS
 
#include <stdio.h>
 
int N;
int numA, numB;
 
int main()
{
    scanf("%d"&N);
    for (register int i = 0; i < N; i++)
    {
        scanf("%d %d"&numA, &numB);
        printf("%d\n", numA + numB);
    }
}
cs


Comments