본문 바로가기

알고리즘/백준알고리즘

[백준알고리즘-JAVA]1546번 풀이(평균)

안녕하세요

인포돈 입니다.



백준 알고리즘 1546번 풀이입니다. 


* 참고사항
 - 개발환경은 eclipse을 기준으로 작성되었습니다.
 - java언어를 이용하여 문제를 풀이합니다.
 - 알고리즘 문제는 풀이를 보고 해답을 찾는 것도 중요하지만 무엇보다 스스로 풀이를 시도해봐야 합니다!!
(해당 풀이를 보기 전 충분히 문제에 대해 고민해봐야 합니다!)
 - 해당 풀이 말고도 수많은 풀이 방법이 존재합니다.


백준 1546 (평균)

 

문제

세준이는 기말고사를 망쳤다. 세준이는 점수를 조작해서 집에 가져가기로 했다. 일단 세준이는 자기 점수 중에 최댓값

 

을 골랐다. 이 값을 M이라고 한다. 그러고 나서 모든 점수를 점수/M*100으로 고쳤다.


예를 들어, 세준이의 최고점이 70이고, 수학 점수가 50이었으면 수학 점수는 50/70*100이 되어 71.43점이 된다.


세준이의 성적을 위의 방법대로 새로 계산했을 때, 새로운 평균을 구하는 프로그램을 작성하시오.

 

입력

첫째 줄에 시험 본 과목의 개수 N이 주어진다. 이 값은 1000보다 작거나 같다. 둘째 줄에 세준이의 현재 성적이 주어진다. 이 값은 100보다 작거나 같은 음이 아닌 정수이고, 적어도 하나의 값은 0보다 크다.

 

출력

첫째 줄에 새로운 평균을 출력한다. 실제 정답과 출력 값의 절대 오차 또는 상대오차가 10-2 이하이면 정답이다.

 

입력 예시

3
40 80 60

출력 예시

75.0

입력 예시

3
10 20 30

출력 예시

66.666667

 

실패 코드

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;


public class Main {
	
	public static void main(String[] args) {
	
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

			try {
				
				int scorenum = Integer.parseInt(br.readLine());
				StringTokenizer stk = new StringTokenizer(br.readLine());
				int[] score = new int[scorenum];
				
				int max=0;
				float sum = 0;
				
				for(int i = 0; i < score.length;i++) {
					if(stk.hasMoreTokens()) {
						int a =Integer.parseInt(stk.nextToken());
						score[i] = a;
						if( max<a) {
							max=a;
						}
					}
				}

				for(int i =0; i < scorenum ; i++) {
					sum = sum + (score[i]*100)/max;
				}

				System.out.println(sum/scorenum);
				
			} catch (Exception e) {
				e.printStackTrace();
			} 
			
			}//main
		}

해당 코드를 작성해봤는데 틀렸다는 답변이 나왔습니다. 해당 문제의 오류를 고심해봤는데 바로 출력에서 나오는 절대 오차에 문제가 있었다고 생각했습니다.

 

나름 고심한다고 해서 sum의 데이터 타입을 float로 지정하였지만, 결론적으로 Score [i]*100/max의 경우 모두 int이기 때문에 소수점 아래의 자리는 모두 버려진다는 것을 알 수 있습니다.

 

기본적으로 데이터 형 변환을 자동으로 할 때는 아래 순서로 진행되게 된다.

int < long < float < double

 

적확히 이해하기 위해서는 아래 코드를 예시로 보여드리겠습니다.

	int a = 100;
	int b = 30;
	float c = a/b;
	
	float d = 100;
	float e = 30;
	float f = d/e;

여기서 a/b는 이미 int형으로 연산을 끝마칩니다. 즉, 3.3333에서 소수점 아래를 버려버리게 되죠. 데이터 손실이 나오게 되고 이는 저희가 풀이하는 문제에 절대 오차 범위를 넘어갑니다.

 

또한 여기서 살펴볼 것은 따로 형 변환을 하지 않아도 알아서 float형식으로 변경되는 점이죠. 즉, 앞에서 설명한 데이터 타입의 순서가 위에 있을 경우 따로 형 변환을 하지 않아도 알아서 형 변환이 일어난다는 점이죠

 

이러한 점을 상기하면서 다시 코드를 재구성하면 아래와 같은 성공코드를 도출해 낼 수 있습니다.

 

성공 코드

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;


public class Main {
	
	public static void main(String[] args) {
	
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

			try {
				
				int scorenum = Integer.parseInt(br.readLine());
				StringTokenizer stk = new StringTokenizer(br.readLine());
				float[] score = new float[scorenum];
				
				int max=0;
				float sum = 0;
				
				for(int i = 0; i < score.length;i++) {
					if(stk.hasMoreTokens()) {
						int a =Integer.parseInt(stk.nextToken());
						score[i] = a;
						if( max<a) {
							max=a;
						}
					}
				}

				for(int i =0; i < scorenum ; i++) {
					sum = sum + (score[i]*100)/max;
				}

				System.out.println(sum/scorenum);
				
			} catch (Exception e) {
				e.printStackTrace();
			} 
			
			}//main
		}

 

해당 문제에서 가장 중요한 점은 바로 데이터의 형 변환에 의해 일어나는 데이터 손실을 최소화시키는 법이라고 할 수 있겠네요. 모두들 이점에 주의하여 문제를 풀이해보세요 ~!!

 


 

해당 문제를 풀이한 다른 분들의 코드를 보면 여러 가지 색다른 풀이법을 알 수 있어요. 그중에 인상 깊게 본 코드는 바로 배열의 정렬 메서드를 이용하여 코드의 길이를 획기적으로 줄여서 문제를 풀이한 답이 있었어요

 

Array.sort(); 해당 메서드를 통해서 좀 더 빠른 속도로 해당 문제를 풀어볼 수 있어요!! 힌트입니다.