[문제]
총 N개의 시험장이 있고, 각각의 시험장마다 응시자들이 있다. i번 시험장에 있는 응시자의 수는 Ai명이다.
감독관은 총감독관과 부감독관으로 두 종류가 있다.
총감독관은 한 시험장에서 감시할 수 있는 응시자의 수가 B명이고, 부감독관은 한 시험장에서 감시할 수 있는 응시자의 수가 C명이다.
각각의 시험장에 총감독관은 오직 1명만 있어야 하고, 부감독관은 여러 명 있어도 된다.각 시험장마다 응시생들을 모두 감시해야 한다.
이때, 필요한 감독관 수의 최솟값을 구하는 프로그램을 작성하시오.
[입력]
첫째 줄에 시험장의 개수 N(1 ≤ N ≤ 1,000,000)이 주어진다.둘째 줄에는 각 시험장에 있는 응시자의 수 Ai (1 ≤ Ai ≤ 1,000,000)가 주어진다.셋째 줄에는 B와 C가 주어진다. (1 ≤ B, C ≤ 1,000,000)
[출력]
각 시험장마다 응시생을 모두 감독하기 위해 필요한 감독관의 최소 수를 출력한다.
해당 문제는 다음과 같은 순서로 구별하고자 했다.
1. 입력 받기
2. 입력 받은 값을 통해 총 시험 감독 수 구하기.
3. 출력하기
입력은 메인 메서드에서 스캐너를 활용하여 받는다.
이 때 처음 입력 받는 값인 시험장 개수를 받고, 각 시험장 마다 인원수를 달리해서 받기에, 시험장 개수를 이용하여 for문을 사용해 시험장의 각 인원수를 입력 받고, 메인 감독이 관리할 수 있는 인원과 서브 감독이 관리할 수 있는 인원도 받아서 전부 변수에 저장했다.
이 때 시험장의 각 인원수는 ArrayList를 사용해서 데이터를 받았다. 시험장의 인원들 하나 하나 구별 해서 사용해서 쓰는 것보다는 구별 하지 않고 순환하여 연산 후 사용할 것이기 때문이다.
입력 받은 값은 getExamSupervisor 메서드를 생성하여 인자로 전달 한다. 이 때 시험장 개수를 전달하지 않은 이유는 ArrayList와 forEach를 사용해서 굳이 필요 없기 때문이다.
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("시험장 개수를 입력");
int examPlace = sc.nextInt();
ArrayList<Integer> examPeople = new ArrayList<Integer>();
System.out.println("시험장 당 인원수 입력");
for (int i = 0; i < examPlace; i++) {
examPeople.add(sc.nextInt());
}
System.out.println("메인 감독 관리 인원");
int main = sc.nextInt();
System.out.println("서브 감독 관리 인원");
int sub = sc.nextInt();
int totalSuperVisor = getExamSupervisor(examPeople, main, sub);
}
메서드 getExamSupervisor는 각 시험장의 인원수와 메인, 서브 감독관의 각 관리 가능 인원수를 받아서 연산한다.
먼저 반환할 변수 총 시험 감독관 인원인 totalSupervisor를 선언하고 여기에 로직으로 카운팅 후 반환할 것이다.
나는 forEach를 이용해서 각 시험장 인원에 따른 감독관 인원을 구하고 더할려고 한다. 그러기에, 감독관 인원 구하는 로직을 forEach를 활용해서 시험장 개수 만큼 순환해 수를 구했다.
시험장의 인원이 메인 감독관의 관리 가능 인원수보다 클 때는 서브 감독관이 필요해진다. 따라서 if문을 사용해서 분기처리를 하였고, 그 안에는 서브 감독관을 구하기 위한 로직을 넣었다.
서브 감독관 수는 먼저 시험장 인원에서 메인 감독관의 관리 인원를 빼고 남은 인원수를 구한다. 그것이 서브 감독관이 관리할 시험장의 인원수다.
그래서 단순하게 남은 인원수에서 서브 감독관의 관리 가능 인원수를 나눌려고 했는 데, 문제가 발생한다. 예시를 들어보자.
시험장 인원 : 5명, 메인 감독관 관리 가능 인원 : 2명, 서브 감독관 관리 가능 인원 : 2명
위와 같은 상황이오면, 서브 감독관이 관리할 인원은 3명이다. 하지만 연산자를 사용해 단순하게 나누면 3/2 -> 1이라는 결과가 되는 데, 이는 정답이 아니다. 이유는 나누기 연산자를 사용하면 나머지가 남아도 정수만 계산하다. 그렇게 되면 3명을 관리할려면 실제로는 2명이 필요한데, 3/2를 사용해 1명이 필요하다는 결과를 도출한다.
이러한 문제를 해결하기 위해 남은 인원수와 관리 가능 인원수를 나눌 때 나머지 여부에 따라 분기처리를 한다.
만약에 나머지가 없다면 그냥 나눠도 문제가 되지 않기에 그렇게 하고, 나머지가 있다면 나눈 값의 결과보다 1명이 더 많아야해서 1을 더 더해준다.
그러고는 무조건 메인 감독관은 1명 필요해서 위의 서브 감독관 로직 후에 메인 감독관, 1명을 더 추가하고 for Each가 끝나면 반환한다.
public static int getExamSupervisor(ArrayList<Integer> examPeople, int main, int sub) {
int totalSuperVisor = 0;
for (int item : examPeople) {
if(item > main){
int other = item - main;
if(other%sub == 0){
totalSuperVisor += other/sub;
} else{
totalSuperVisor += (other/sub) + 1;
}
}
totalSuperVisor++;
}
return totalSuperVisor;
}
마지막으로는 메인 메서드에서 메서드를 호출하여 결과를 변수에 저장하고 출력하면 끝이다.
int totalSuperVisor = getExamSupervisor(examPeople, main, sub);
System.out.println(totalSuperVisor);
[코드]
import java.util.ArrayList;
import java.util.Scanner;
public class ExamSupervisor {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("시험장 개수를 입력");
int examPlace = sc.nextInt();
ArrayList<Integer> examPeople = new ArrayList<Integer>();
System.out.println("시험장 당 인원수 입력");
for (int i = 0; i < examPlace; i++) {
examPeople.add(sc.nextInt());
}
System.out.println("메인 감독 관리 인원");
int main = sc.nextInt();
System.out.println("서브 감독 관리 인원");
int sub = sc.nextInt();
int totalSuperVisor = getExamSupervisor(examPeople, main, sub);
System.out.println(totalSuperVisor);
}
public static int getExamSupervisor(ArrayList<Integer> examPeople, int main, int sub) {
int totalSuperVisor = 0;
for (int item : examPeople) {
if(item > main){
int other = item - main;
if(other%sub == 0){
totalSuperVisor += other/sub;
} else{
totalSuperVisor += (other/sub) + 1;
}
}
totalSuperVisor++;
}
return totalSuperVisor;
}
}
'CS > 알고리즘 문제' 카테고리의 다른 글
[백준 - 1712] 손익 분기점 (0) | 2022.08.29 |
---|---|
[백준 - 4344] 평균은 넘겠지(배열 응용) (0) | 2022.08.26 |
[백준 - 1110] 새로운 수 찾기 (0) | 2022.08.26 |
[백준 - 2480] 3개의 주사위 게임 (0) | 2022.08.26 |