문제 접근
- 산술 평균의 경우, 값을 입력받을 때마다 N으로 나눈 것들의 총합을 구해 반올림하자.
총합은 반올림을 위해 실수 자료형을 사용했기에, 모두 더하고 나누면 오버플로우가 발생할 수 있음. - 중앙값의 경우, 단순히 입력받은 값 vector를 정렬해서 중앙값을 가져오자.
algorithm 헤더의 sort 함수는 O(nlogn)이다. 따라서, N이 최댓값(500,000)이라고 하더라도 대략 3백만으로 충분히 시간 내에 해결 가능함. - 최빈 값의 경우, 중복 횟수를 세는 vector를 만들어서 max_element 함수로 최빈값을 찾자.
최빈 값이 여러 개라면 max_element 함수가 가장 첫 번째 max 값의 iterator를 반환하므로, 첫 번째 iterator 다음부터 end까지 중 max 값과 같은 게 있다면 해당 iterator의 수를 출력하고, 없다면 첫 번째 iterator의 수를 출력함. - 범위의 경우, 입력 받은 값 vector를 정렬한 것의 마지막 값에서 첫 번째 값을 빼서 구하자.
https://www.acmicpc.net/problem/2108
2108번: 통계학
첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 단, N은 홀수이다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.
www.acmicpc.net
문제 코드
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
int main(void)
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int N, tmp, mode_idx;
double total = 0;
vector<int> mode(8001, 0);
vector<int> input;
cin >> N;
for (int i = 0; i < N; ++i)
{
cin >> tmp;
total += (double)tmp/N;
++mode[tmp+4000];
input.push_back(tmp);
}
sort(input.begin(), input.end());
cout << floor(total + 0.5) << '\n';
cout << input[N / 2] << '\n';
mode_idx = max_element(mode.begin(), mode.end()) - mode.begin();
if (mode.begin() + mode_idx + 1 != mode.end() && *max_element(mode.begin() + mode_idx + 1, mode.end()) == mode[mode_idx])
{
cout << max_element(mode.begin() + mode_idx + 1, mode.end()) - mode.begin() - 4000 << '\n';
}
else
cout << mode_idx - 4000 << '\n';
cout << input[N - 1] - input[0] << '\n';
return 0;
}
느낀 점
오늘은 class 2++에서 풀지 않은 문제들을 풀어봤다. 무리하게 목표를 이루기 위해 빨리 진도를 나가기보다는 지금처럼 조금씩 깨닫게 되는 것들을 정리하며 나아가도 좋을 것 같다.
추가로, 알고리즘 문제를 풀고 나서 언어 문법 관련해서 애매한 부분이 있으면 <C++ 기초 플러스>를 참고하고 있는데, 이전처럼 정독하려고 애를 쓰기보다는 지금처럼 필요할 때마다 읽는 게 더 좋아 보인다.
앞으로도 오늘처럼 꾸준히 그리고 천천히 해보려고 한다. 이번 문제를 풀며 느낀 점으로 풀이를 마무리 짓겠다.
- 음수 나눗셈을 조심하자.
이번 문제에서는 큰 문제가 되지 않았지만, 음수 나눗셈의 경우, 나머지가 음수로 나오기도 하니 추후에 음수 값의 나머지를 구하는 문제가 나오면 이 점 유의하자. - 조건식이 꼭 필요한지 확인하자.
무조건 참이거나 거짓인 조건이 불필요하게 조건식에 들어가있는지 확인해 보자. 솔직히 코드가 길든, 짧든 맞기만 하면 되긴 하는데 나는 되도록이면 알고리즘 풀이더라도 깔끔한 코드를 작성하고 싶다. - 반례를 찾는 걸 의식적으로 하면서, 나만의 순서를 만들어보자.
예제는 다 맞았는데 틀린 경우, 반례를 찾기 되게 귀찮아한다. 이전에는 머리 깨지고 삽질하면서 하긴 했는데, 이번에는 그래도 조금은 더 똑똑하게 머리를 깨고 싶다.
이번 문제도 예제는 맞는데 결과는 틀리길래, '맞왜틀.. 맞왜틀..'거리고 있다가 float 자료형의 실수 계산이 정밀하지 않다는 걸 알고, total을 double 자료형으로 바꾸니 해결됐다.
논리가 아니라 동작 원리에 의해 틀리는 경우도 있으니 이를 확인하는 나만의 순서를 만들어보면 좋을 것 같다.
'개발 > 알고리즘' 카테고리의 다른 글
백준 2231번 : 분해합 (0) | 2023.02.14 |
---|---|
백준 1929번 : 소수 구하기 (0) | 2023.02.14 |
백준 1874번 : 스택 수열 (0) | 2023.02.13 |
2023 알고리즘 레콩키스타 - 시작 (1) | 2023.02.01 |
[Codeforce] Educational Codeforces Round 115 (Rated for Div. 2) 풀이 (0) | 2022.07.02 |