본문 바로가기

알고리즘/백준알고리즘

[백준알고리즘-JAVA]4344번 풀이(평균은 넘겠지)

안녕하세요

인포돈입니다.



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


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


백준 4344 (평균은 넘겠지)

 

문제

대학생 새내기들의 90%는 자신이 반에서 평균은 넘는다고 생각한다. 당신은 그들에게 슬픈 진실을 알려줘야 한다.

입력

첫째 줄에는 테스트 케이스의 개수 C가 주어진다.
둘째 줄부터 각 테스트 케이스마다 학생의 수 N(1 ≤ N ≤ 1000, N은 정수)이 첫 수로 주어지고, 이어서 N명의 점수가 주어진다. 점수는 0보다 크거나 같고, 100보다 작거나 같은 정수이다.

출력

각 케이스마다 한 줄씩 평균을 넘는 학생들의 비율을 반올림하여 소수점 셋째 자리까지 출력한다.

입력 예시

5
5 50 50 70 80 100
7 100 95 90 80 70 60 50
3 70 90 80
3 70 90 81
9 100 99 98 97 96 95 94 93 91

출력 예시

40.000%
57.143%
33.333%
66.667%
55.556%

성공코드

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


public class Main {
	
	public static void main(String[] args) throws IOException{
	
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
				
				int casenum = Integer.parseInt(br.readLine());
				double[] db = new double[casenum];

				for(int i = 0 ; i < casenum ; i++) {
					double c = 0;
					double sum = 0;
					double count = 0;
					
					StringTokenizer stt = new StringTokenizer(br.readLine());
					c = Integer.parseInt(stt.nextToken());
					double[] input = new double[(int)c];
					
					//input change doubleArray & sum
					for(int k=0; k < c;k++) {
						if(stt.hasMoreTokens())
						input[k] = Double.parseDouble(stt.nextToken());
						sum += input[k];
					}
					
					//subject average
					for(int l=0;l<c;l++) 
						if( input[l] > sum/c) 
							count ++;
						
					db[i] = (count/c)*100;
				}
				
				for(double d : db) {
					System.out.println(String.format("%.3f", d) + "%");
				}	
			
			}//main
		}

해당 코드에서 핵심사항은 크게 2가지로 생각이 된다.

 

어떻게 평균을 넘는 비율을 표현할 것인가?

어떻게 소수점 3자리에서 반올림을 하여 표현할 것인가?

 

이 두 가지 의문을 차례차례 풀이해 보겠습니다.


어떻게 평균을 넘는 비율을 표현할 것인가?

 

해당 의문을 해결하기 위해서 무엇이 필요할까요?

 

입력의 첫 번째 예시를 생각해보죠

5 50 50 70 80 100

5개의 점수가 있습니다. 우선 평균을 알아야 넘는 비율을 알 수 있겠죠?

 

평균을 구해보면 70점인 것을 알 수 있습니다. 평균이 70점이니 저 중에 70점을 넘기는 점수는 80점 100점이 있죠

 

그렇다면, 5개 중 2개가 평균을 넘는 거죠 2/5 = 0.4 여기에 백분율로 표현하기 위해 100을 곱하면 40% 저희가 원하는 결과 값이 나오죠.

 

슬슬 감이 오신 분도 있을 겁니다.

 

 - 배열에 해당 점수들을 넣는다.

 - 해당 점수들의 평균을 구한다.

 - 조건문을 활용하여 평균을 넘는 점수들을 count 한다.

 - 평균 이상 비율을 출력한다.

 

이런 식으로 큰 윤곽을 잡을 수 있죠


두 번째 의문인 어떻게 소수점 3자리에서 반올림하여 출력을 할까?

 

이문제는 검색을 통해 쉽게 찾을 수 있습니다.

 

소수점 반올림을 위해서는 대표적으로 String.format방식과 Math.round방식이 있습니다.

 

1. Math.round()

double pie = 3.14159265358979;
System.out.println(Math.round(pie)); //결과 : 3
System.out.println(Math.round(pie*100); //결과 : 314
System.out.println(Math.round((pie*100)/100.0); //결과 : 3.14

pie*100을 하면 314 값이 반환이 됩니다. 거기에 다시 100을 나누어주면 3.14 반올림이 된 걸 알 수 있죠

 

 

2. String.format()

double pie = 3.14159265358979;
System.out.println(String.format("%.2f", pie)); //결과 : 3.14
System.out.println(String.format("%.3f", pie)); //결과 : 3.142

쉽게 해결할 수 있습니다 %. 2f 즉, 소수점 2번째 자리에 반올림을 하라는 소리죠

 

2가지 방법 중 편하실걸을 이용하셔서 풀이하시면 됩니다.

 


 

그러나!!!! 저희는 언제나 더 나은 방법을 생각해볼 필요가 있습니다. 제가 작 상한 코드는 속도나 메모리를 잡아먹는 면에서 굉장히 비효율 적인 것을 알 수 있죠. 그래서 print대신 Bufferedwriter을 이용해서 다시 작성해보았습니다.

 

다른 성공 코드

import java.io.*;
import java.util.StringTokenizer;


public class Main {
	
	public static void main(String[] args) throws IOException{
	
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
				
				int casenum = Integer.parseInt(br.readLine());
				double[] db = new double[casenum];

				for(int i = 0 ; i < casenum ; i++) {
					double c = 0;
					double sum = 0;
					double count = 0;
					
					StringTokenizer stt = new StringTokenizer(br.readLine());
					c = Integer.parseInt(stt.nextToken());
					double[] input = new double[(int)c];
					
					//input change doubleArray & sum
					for(int k=0; k < c;k++) {
						if(stt.hasMoreTokens())
						input[k] = Double.parseDouble(stt.nextToken());
						sum += input[k];
					}
					
					//subject average
					for(int l=0;l<c;l++) 
						if( input[l] > sum/c) 
							count ++;
						
					db[i] = (count/c)*100;
					bw.write(String.format("%.3f", db[i]) + "%");
					bw.write("\n");
				}
				bw.flush();
				bw.close();
				br.close();
			
			}//main
		}

이것보다 더 빠르게 하신 순위권들 분들도 있어서 어떻게 그렇게 했는지 복사하여 제 컴퓨터로 제출해봤는데, 순위권들과는 또 다른 속도와 메모리 사용량을 보여주더군요.

 

이를 보면, 똑같은 코드여도 속도나 메모리 사용량이 달라질 수 있음을 알 수 있고 정확한 이유는 아직 찾지 못했네요 ㅜㅜ 나중에 알게 되면, 알려드리겠습니다 ~