백준 C++ 풀이에서는 알고리즘만큼 입력 처리, 빠른 입출력, 헤더 구성, 디버깅 습관이 제출 결과를 좌우합니다.
공백이 포함된 문자열은 getline으로 받고, 대량 입력은 ios::sync_with_stdio(false)와 cin.tie(nullptr) 설정을 쓰되 C 입출력과 섞지 않는 편이 안전합니다.
핵심 정리
C++로 백준 문제를 풀 때 자주 막히는 지점은 알고리즘보다 입출력 형식입니다. cin 뒤에 getline을 바로 쓰면 남아 있는 개행 때문에 빈 줄이 들어올 수 있고, 빠른 입출력을 켠 뒤 scanf와 printf를 섞으면 예상하지 못한 문제가 생길 수 있습니다. bits/stdc++.h는 온라인 저지의 GCC 환경에서는 편하지만 표준 헤더는 아니므로, 다른 컴파일러 환경에서는 필요한 헤더를 직접 포함하는 방식도 알아 두는 것이 좋습니다.
- 공백이 포함된 한 줄 입력은 getline으로 처리합니다.
- cin 뒤에 getline을 쓸 때는 남은 개행 문자를 처리해야 합니다.
- 입력량이 크면 빠른 입출력 설정으로 시간 초과 위험을 줄일 수 있습니다.
- 빠른 입출력 설정 후에는 C 입출력 함수와 섞지 않는 편이 안전합니다.
- bits/stdc++.h는 편리하지만 GCC 중심의 비표준 헤더입니다.
- 문제 풀이용 디버그 출력은 제출 전에 반드시 제거하거나 조건부로 막아야 합니다.
- 반복되는 입력, 출력, 컨테이너 확인 코드를 습관화하면 구현 시간이 줄어듭니다.
원문은 getline과 빠른 입출력, 헤더 사용 메모가 섞여 있으므로, 실전에서 자주 틀리는 입력 처리 순서와 제출 전 확인 포인트를 먼저 보이도록 정리했습니다.
이어서 볼 글
- 백준 제출 오류 유형과 해결 방법 정리 - 입출력 실수 이후 실제 제출 판정별로 어디를 확인할지 정리한 글이다.
- C언어 문자열 입력: scanf, fgets, 공백 포함 한 줄 읽기 - getline, 공백 포함 입력, 개행 처리 문제를 C 입력 함수 관점에서 보완한다.
c++에서 string 입력받기
이 문제에서 처럼, 공백이 포함된 한 줄 전체를 string에 받아올 일이 있을때는 아래처럼 getline을 쓰면 된다.
|
1
2
|
string str;
getline(cin, str);
|
cs |
c++로 입출력하기
앞에거는 printf,scanf랑 페어링 끄기, 뒤에거는 입출력반복될때 처리에 대한것
|
1
|
ios::sync_with_stdio(0);cin.tie(0);
|
cs |
이거 하고 나면 printf, scanf쓰면 안된다.
헤더파일 단순화 하기
알고리즘 문제를 풀다보면 다음과 같이 헤더파일이 점점 길어지고 지저분해짐을 알 수 있다.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <set>
#include <stack>
#include <queue>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <map>
using namespace std;
int dp[2][1000000+1];
int main(void)
{
|
cs |
그 이유는 매번 문제마다 필요한 vector, map, string등을 그때 그때 추가하다보면 귀찮아서져 그냥 슈퍼셋으로 들고가게 되는 현상이 나타난다(...)
근데 gcc에서만 지원하긴하지만 다음처럼 <bits/stdc++h>를 쓰면 헤더파일이 무척 깔끔해진다. 자주쓰는 헤더들을 모아서 처리해주는 역할을 해주기 때문이다.
|
1
2
3
4
5
6
7
|
#include <bits/stdc++.h>
using namespace std;
int main(void)
{
return 0;
}
|
cs |
표준은 아니라서 visual c++나 xcode에서는 잘 안되는데,
xcode 기반의 clion을 쓰는 내 경우는 여기 링크에 나온대로 stdc++.h파일을 복사한다음에 다음경로에 설정해주니 잘 되었다.
만약에 bits/stdc++.h의 경로를 못찾겠다고 나오면,
CMakeLists.txt를 열어서 다음 부분을 추가해주면 되었다(include_directories 부분)

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1
mac에서 그냥 c++을 쓰는경우 (visual studio code등에서 사용) 다음 경로에 설정해주면 된다.
/usr/local/include
visual studio를 쓰는 경우는 아래 링크에 복사
D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.31.31103\include
그래프 그려주는 툴
https://csacademy.com/app/graph_editor/ 정말 짱인거 같다.
stl을 printf-style로 디버깅하기
visual studio가 라인디버깅 성능이 막강하긴 하지만, PS를 하다가 그렇게 하다보면 시간이 너무 많이 흘러가게 된다.
따라서 간단하게 vector나 map등을 print로 찍어보면 좋은데, built-in으로는 그러한 함수가 없고 반드시 루프를 돌려야 한다.
여기 있는 헤더를 include하면 그러한 점을 보완해준다.
간단하게 사용법을 보려면 다음 예제를 보자.
|
1
2
3
4
5
6
7
8
9
|
#include <bits/stdc++.h>
#include "dbg.h" // https://github.com/sharkdp/dbg-macro
using namespace std;
int main()
{
map<int, string> m = { {1,"abc"}, {2,"cde"} };
dbg(m);
return 0;
}
|
cs |
dbg()로 감싸주기만 하면 그내용을 다음처럼 출력해준다.
|
1
|
[..\nothing\nothing.cpp:7 (main)] m = {{1, "abc"}, {2, "cde"}}
|
cs |
물론 온라인저지에 이대로 제출할수는 없기 때문에(커스텀 헤더라, 저지 서버에서는 인식못하고, 속도도 떨어뜨릴거고)
다음과 같이 감싸주는 부분이 필요하다.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#include <bits/stdc++.h>
using namespace std;
#ifdef WIN32
#include "dbg.h" // https://github.com/sharkdp/dbg-macro
#else
#define dbg(...)
#endif
int main()
{
map<int, string> m = { {1,"abc"}, {2,"cde"} };
dbg(m);
return 0;
}
|
cs |
나는 간단하게 WIN32으로 감싸주었지만, 좀 더 고민해서 잘 감싸는게 필요할지도 (-DONLINE_JUDGE등 사용)
입력개수가 명시되지 않은 입력을 받는법
예를 들어 이 문제의 경우 입력개수 없이 받도록 되어 있다.
while(cin << n) 이렇게 받는걸로 추천되어 있다.
c스타일로 받을경우는 다음처럼 하면 된다.
|
1
2
3
4
|
int n;
while(scanf("%d", &n)!=EOF){
//do something
}
|
cs |
이 문제에서 연습할 수 있다.
freopen 사용하기
백준에서는 ONLINE_JUDGE를 define하고 있으므로 다음과 같이 사용하면 파일로 입력을 줄 수 있다.
|
1
2
3
|
#ifndef ONLINE_JUDGE
freopen("input.txt", "rt", stdin);
#endif
|
cs |
char를 입력받는 방법
이 문제를 보면 숫자를 입력받은 다음에 char를 입력받게 되어 있는데 생각없이 scanf("%d") 한다음에 scanf("%c")를 하게 되면 \n char 때문에 제대로 안된다. 방법은 scanf("%c") 대신에 scanf("\n%c")로 해주면 되긴했다.
또는 숫자는 scanf("%d") 로 받고 그다음은 scanf("%s")로 문자열로 받아서 문자열 파싱을 해도 됨
EOF까지 입력받기
이 문제와 같이 N이주어지는게 아니라 단순히 EOF까지 입력을 받으라는 경우가 있다.
이때는 C언어의 경우는 다음처럼 scanf의 리턴값이 EOF임을 체크하면 된다.
#include <cstdio>
int main() {
int n;
while (scanf("%d", &n) != EOF) {
// process the input
}
return 0;
}
개행문자까지 문자열을 읽는 방법
3 @ %
10.4 # % @
8 #
위와 같이 어쩔때는 문자가 2개 (@ X), 어쩔때는 문자가 3개 (# % @), 어쩔때는 문자가 한개(#) 주어질때,
아래처럼 %[^\n]를 쓰면 개행문자까지 문자열을 읽을 수가 있다.
double A;
char s[10] = {};
scanf("%lf %[^\n]", &A, s);
for (int i = 0; s[i] != '\0'; ++i) {
if (s[i] == '@') A *= 3;
else if (s[i] == '%') A += 5;
else if (s[i] == '#') A -= 7;
}
이 문제를 참조하자.
'Programming > Problem Solving' 카테고리의 다른 글
| C++ bigint class: 큰 정수 덧셈과 임의 정밀도 (1) | 2020.03.30 |
|---|---|
| 백준 9663 N-Queen 풀이: 대각선 체크와 백트래킹 (0) | 2020.03.15 |
| C++ 행렬곱 구현: 2차원 배열과 vector 행렬 패턴 (0) | 2020.03.01 |
| C언어 문자열 입력: scanf, fgets, 공백 포함 한 줄 읽기 (0) | 2020.02.21 |
| 백준 제출 오류 유형과 해결 방법 정리 (0) | 2019.03.18 |
