백준 문제 15552번의 가장 큰 핵심포인트!
cin.tie(NULL)
과ios_base::sync_with_stdio(false)
그리고endl
에 대해 알아보자
문제를 풀기에 앞서 문제 내용에 이런 문장이 있다.
"C++을 사용하고 있고 cin/cout을 사용하고자 한다면, cin.tie(NULL)과 sync_with_stdio(false)를 둘 다 적용해 주고, endl 대신 개행문자(\n)를 쓰자. 단, 이렇게 하면 더 이상 scanf/printf/puts/getchar/putchar 등 C의 입출력 방식을 사용하면 안 된다."
시간을 줄이기 위한 키포인트 같은데..
뭔지는 알고 적용해야 할 것 같아서 알아보았다.
👉 cin.tie(NULL)
과 ios_base::sync_with_stdio(false)
은 대게 main의 첫번째 줄에 작성한다.
💡 ios_base::sync_with_stdio(false)
: C의 stdio와 C++의 iostream의 동기화를 비활성화 한다 (즉, 평소엔 서로 동기화 상태)
기본적으로 C++와 C의 표준 스트림은 동기화되어있다. 즉, C++에서 C와 C++ 각각의 스타일로 입출력을 받아도 서로 동기화해 우리가 입력/출력하고자 하는 순서대로 결과를 얻을 수 있다. C와 C++가 동일한 버퍼를 공유한다는 것이다.
ios_base::sync_with_stdio(false)
을 통해 동기화를 끊으면 C++ 표준 스트림이 독립적으로 IO 버퍼링을 하게 되어 많은 양의 입출력이 있을 경우 성능이 많이 좋아진다.
💡 cin.tie(NULL)
: 입력과 출력 연결을 끊어준다 (cin.tie(nullptr)
또는 cin.tie(0)
도 가능)
원래 cout
와 cin
, 입출력은 묶여있다.
입력요청이 들어오면 그 전에 출력 작업이 있었을 경우(출력 버퍼에 내용이 있는 경우) 버퍼를 비워(flush) 출력하게 된다.
cin.tie(NULL)
을 통해 입출력 묶음을 풀면 시간이 단축된다.입출력 순서를 보장받을 수 없다.
예를 들어 좀 더 자세히 설명해보겠다.
[입출력이 묶여있는 경우]
#include<iostream>
using namespace std;
int main(void){
ios_base::sync_with_stdio(false);
int t,num1,num2;
cin>>t;
for(int i=0;i<t;i++){
cin>>num1>>num2;
cout<<num1+num2<<"\n";
}
}
이때, 입력과 출력은 순서대로 이루어진다.
입력 한 번에 출력이 매번 이루어지는 것이다.
2 //test case
1 1 //입력
2 //출력
2 2 //입력
4 //출력
[입출력 묶음이 풀려있는 경우]
#include<iostream>
using namespace std;
int main(void){
cin.tie(NULL); //입출력 묶음 해제
ios_base::sync_with_stdio(false);
int t,num1,num2;
cin>>t;
for(int i=0;i<t;i++){
cin>>num1>>num2;
cout<<num1+num2<<"\n";
}
}
이 경우, 입출력이 순서대로 출력되지 않는 걸 볼 수 있다.
2 //test case
1 1 //입력
2 2 //입력
2 //출력
4 //출력
입력을 한 번에 받고, 출력이 나중에 한 번에 처리된다.
즉, 매번 출력을 비우지(flush)않고 나중에 한 번에 비우도록 하는 것이다.
endl
은 개행 뿐만아니라 출력 버퍼를 비우는(flush) 역할도 한다.
+) endl
은 출력 버퍼를 비우기 때문에 위에서 다룬 cin.tie(NULL)
의 역할인 묶음을 끊어주는 효과를 볼 수 없게 한다.
["\n"대신 endl을 사용할 경우]
#include<iostream>
using namespace std;
int main(void){
cin.tie(NULL); ios_base::sync_with_stdio(false);
int t,num1,num2;
cin>>t;
for(int i=0;i<t;i++){
cin>>num1>>num2;
cout<<num1+num2<<endl;
}
}
분명 cin.tie(NULL)
을 작성했음에도 endl
이 출력 버퍼를 비워 입력과 출력이 순서대로 이루어지는 결과를 볼 수 있다.
2 //test case
1 1 //입력
2 //출력
2 2 //입력
4 //출력
15552번 문제 제출하면서 cin.tie(NULL)
과 ios_base::sync_with_stdio(false)
를 뺀 경우와, endl
을 적용시킨 두 경우 모두 제출해보았는데 둘 다 시간초과 가 떴다!