07 Dec 2022

<aside> ❗ 60ms, 8ms로 푸는 방법이 있다고? 174ms로의 c++ 최적화와 Rust는 어떻게 1/3 속도로 처리하는지 궁금하다면 계속 읽어보자!

</aside>

백준 15552번은 ‘이것’을 모르면 시간 초과가 나와서 풀 수 없는 문제이다. 다른 수많은 블로그에도 나와있겠지만, std::ios::sync_with_stdio(false)와 std::cin.tie(NULL)을 써 주고, std::endl대신 ‘\n’을 써야 제 시간에 풀기가 가능하다.

왜 빨라지는지 찬찬히, 자세하게 설명해 놨으니 궁금하면 클릭해 보자! 이유도 모르고 기계적으로 쓰기 보다는 알고 가자!

속도가 향상되는 이유에 대해서는 위에 링크에서 확인해 보도록 하고, 그것보다 남들이 하지 않은 가능한 여러 최적화 방법에 대해 알아볼 것이다. 가장 스탠다드한 코드부터 가장 빠른 코드까지 알아보자.

서버의 컨디션은 코드의 실행 속도에 영향을 준다. 같은 코드라고 해도 어떨 때는 265ms가 나오는가 하면 컨디션이 좋을 때는 180ms까지 나온다. 대략 100ms의 오차가 존재할 수 있다는 것을 알아두자.

필자는 요즘은 이런 간단한 문제를 최적화하고 속도 신기록을 세우는 데에 혈안이 되어 있다. 이게 뭐라고 싶겠지만 하다 보면 나름 재미있다. 계속 알아보자.

Table of contents


가장 스탠다드 한 방법 (~220ms)

#include <iostream>
using namespace std;
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    int a, b;
    cin >> t;
    for (int i = 0; i < t; i++)
    {
        cin >> a >> b;
        cout << a + b << '\\n';
    }
}

stdio 동기화를 끊어 주고 tie를 끊어 준다. int 3개를 정의하고 t만큼 반복문을 돌려 a + b를 출력한다. 별로 특이할 게 없는 코드다.

for 문 안에서 int a, b를 정의하기보다 for 문 밖으로 빼는 것이 보기에 조금 더 깔끔한 것 같다. 성능 상의 차이는 거의 무의미할 것이다.

가끔 다른 풀이를 보다 보면 std::cout.tie(nullptr)로 cout의 tie를 끊는 코드들이 보이는데, cout은 애초에 다른 stream과 tie가 되어있지 않다. std::cout.tie()를 호출해보면, 0, 즉 nullptr을 return하는것을 확인할 수 있다.

이 방법이 printf()를 사용하는 방법보다 조금은 빠르다. printf()를 쓰는 방삭이 iostream을 include하지 않는 것만으로도 메모리 상으로 약 1000kb의 이점은 있지만 현대 컴퓨터에서 이정도 메모리 차이는 무의미하다. 속도는 대략 130ms차이 정도이다.