본문 바로가기

프로그래밍/PS

[C++] 백준 6986번: 절사평균

반응형

풀이과정

1. 수열을 벡터로 입력받고, STL sort 함수로 정렬한다.

2. 절사평균은 \(\frac{\sum_{i=K}^{N-K-1}{arr[i]}}{N-2K}\)의 값을 출력한다.

3. 보정평균은 \(\frac{arr[K]\times{K}+arr[N-K-1]\times{K}+\sum_{i=K}^{N-K-1}{arr[i]}}{N}\)의 값을 출력한다.

주의사항

1. 벡터의 형식은 double이다.

2. 출력할 때, 다음과 같이 해야 소숫점 아래 3번째 자리에서 반올림을 하여 표시된다. 뿐만 아니라 소숫점 아래 2번째 자리까지의 표시가 고정된다.

cout.precision(2);
cout << fixed;

3. 실수 데이터 타입에서의 오차

https://www.youtube.com/watch?v=T9l891a0f3o

위 영상에서 처럼, 소숫점을 메모리에 저장할 때 대부분의 수에서 오차가 발생하게 된다. 소숫점 아래가 \(2^{-1}, 2^{-2}, ...\)과 같은 수가 아니면 무한소수가 되기 때문에 무조건 오차가 발생할 수 밖에 없다. 따라서 출력할 때, 반올림에서 문제가 생길 수 있는데, 예를 들면 다음과 같은 경우다.

4.45로 저장되어야 할 수가 4.44999999999999로 저장된 경우. 이 경우에는 소숫점 아래 셋째 자리에서 반올림하면 4.5가 되어야 할 수가 4.4가 돼 버린다. 따라서 적당한 수를 더해줌으로써 이를 해결해야되는데, 나는 1e-13 정도의 수를 더해줌으로써 해결했다. 다만 1e-15부터는 의미가 없게되니 주의해야한다. 1e-15는 0이 된다.

코드

#include <bits/stdc++.h>

using namespace std;

#define TC(T) int T; cin >> T; while(T--)
#define FAST_IO cin.tie(NULL); ios::sync_with_stdio(false);
#define FOR(i, N) for(int i = 0; i < N; ++i)
#define INF 987654321
#define ERR 1e-13
#define EL "\n"

int main() {
#ifdef DEBUG
	freopen("input.txt", "r", stdin);
	//	freopen("output.txt", "w", stdout);
#endif
	FAST_IO;

	int N, K;
	cin >> N >> K;

	vector<double> arr(N);
	FOR(i, N)
		cin >> arr[i];
	sort(arr.begin(), arr.end());

	double trimmed = 0.0;
	for (int i = K; i < N - K; ++i)
		trimmed += arr[i];
	trimmed /= (N - 2 * K);

	cout.precision(2);
	cout << fixed;
	cout << trimmed + ERR << EL;

	double adjusted = arr[K] * K + arr[N - K - 1] * K;
	for (int i = K; i < N - K; ++i)
		adjusted += arr[i];
	adjusted /= N;
	
	cout.precision(2);
	cout << fixed;
	cout << adjusted + ERR << EL;

	return 0;
}
반응형