필요한 장난감의 최소 개수 구하기 문제 풀이 (너비 우선 탐색 이용, BFS)
출처 : 프로그래밍 대회에서 배우는 알고리즘 문제해결 전략
난이도
상
문제
어린이집을 경영하는 원석이는 어린이날을 맞아 어린이집에 다니는 n명의 아이들에게 장난감을 나눠 주기로 마음 먹었습니다.
모든 아이들에게 같은 수의 장난감을 주려고 했지만, 그중 m(0<=m<=n)명의 욕심쟁이 어린이들은 모두 같은 개수의 장난감을 받으면 삐져버립니다.
따라서 이 욕심쟁이 어린이들에게는 남들보다 장난감을 하나씩 더 주기로 했습니다.
종교적인 이유로 인해, 아이들에게 나누어 주는 장난감의 총 수 c는 십진수로 썼을 때 특정 숫자만으로 구성 되어야 합니다.
예를 들어 특정 수가 1과 2라고 하면 n이 5이고 m이 2일때 12개, 112개, 1112개 ... 의 장난감이 필요합니다.
예산이 빠듯한 관계로 장난감을 가능한 적게 사려고 합니다.(12개)
위와 같은 조건을 만족하는 최소의 c를 계산하는 프로그램을 작성하세요.
단, 모든 어린이가 장난감을 하나씩은 받아야 합니다.
시간 및 메모리 제한
프로그램은 2초 안에 실행되어야 하며, 64MB 이하의 메모리를 사용해야 합니다.
입력
입력의 첫 줄에는 테스트 케이스의 수 t (t<=50) 가 주어집니다.
각 테스트 케이스는 c에 사용할 수 있는 자릿수의 목록 d와 n, m (0<=m<n<=10000) 으로 주어집니다.
자릿수 목록은 최소 한개의 숫자는 포함하며, 자릿 수 목록에 한 숫자가 2번 주어지는 일은 없습니다.
출력
각 테스트 케이스마다 필요한 최소 장난감의 수를 출력합니다.
만약 모든 조건을 만족하는 장난감의 개수를 찾을 수 없을 경우, IMPOSSIBLE을 출력합니다.
예제입력
5
1 7 0
1 10 1
0 7 3
345 9997 333
35 9 8
예제 출력
111111
11
IMPOSSIBLE
35355353545
35
풀이
들어가기 앞서, 제가 푼 문제의 정답은 위 예제 출력의 결과와 다르게 나왔음을 알려드립니다.
해당 결과는 입력 345 9997 333 에 관한 것이며, 예제 출력의 결과인 35355353545 보다 작은 수가 나왔습니다.
그런데, 직접 계산기로 계산을 해보니, 정답이 맞습니다. 그래서 수정 없이 올립니다.
만약 제 풀이가 틀렸다면, 말씀해주시면 감사하겠습니다.
저는 아래와 같은 방법으로 풀었습니다.
필요한 사탕의 수를 x라고 했을 때 최소 개수 F(x)는
F(x) = n * x + m 을 만족할 것 ( n 명 중 m 명에게만 1개씩 더 )
너비 우선 탐색으로 조합된 숫자로 이루어진 값을 a 라고 했을 때
a % F(x) = 0 인지 확인하는 문제라고 판단
이때, F(x) < "전체 사탕의 개수" 를 만족해야 한다.
깊이 우선 탐색이 아닌, 너비 우선 탐색으로 숫자를 조합해보아야 하는 이유는,
"최소값"을 찾아야 하기 때문이다.
package BFS;
import java.util.*;
public class three {
// 탐색 시작
static long search(long[] num, long n, long m) {
// 탐색된 수가 들어갈 공간
Map<Long, Long> searched = new TreeMap<>();
// 탐색할 수가 들어갈 공간
Queue<Long> candidate = new LinkedList<>();
/* num을 먼저 정렬하도록 한다. */
Arrays.sort(num);
// 초기화
for (int i=0; i<num.length; i++) {
// 트리 맵에 1자리 숫자로 이루어진 수를 넣는다.
searched.put(num[i], (long)0);
candidate.add(num[i]);
}
while(!candidate.isEmpty()) {
// 탐색할 대상이 되는 장난감 개수
long here = candidate.poll();
// 탐색한 회수 => 이 문제 풀이에서는 의미없는 값입니다.
long cost = searched.get(here);
for (long x=1, smallest = 0; smallest < here; x++) {
// 조건을 만족하는 장난감 개수
smallest = n*x+m;
// 조건에 맞는 숫자를 찾으면 멈춘다.
if (here % smallest == 0) {
return here;
}
}
// 배열을 돌려가면서 하나씩 뒤에 숫자를 붙여본다. => 이때 num은 정렬되어 있으므로 작은 숫자 순서로 정렬한다.
for (int i=0; i<num.length; i++) {
// 다음 숫자를 뒤에 붙여본다.
long there = here * 10 + num[i];
if (!searched.containsKey(there)) {
// here 탐색 완료 => there의 깊이 세팅
searched.put(there, cost+1);
// 탐색할 목록에 there 을 넣는다.
candidate.add(there);
}
}
}
return -1;
}
public static void main(String[] args) {
long[] input1 = {1};
long[] input2 = {1};
long[] input3 = {0};
long[] input4 = {3,4,5};
long[] input5 = {3,5};
long result1 = search(input1, 10, 1);
long result2 = search(input2, 7, 0);
long result3 = search(input3, 7, 3);
long result4 = search(input4, 9997, 3333);
long result5 = search(input5, 9, 8);
System.out.println(result1);
System.out.println(result2);
System.out.println(result3);
System.out.println(result4);
System.out.println(result5);
}
}
결과
11
111111
-1
4435343
35
여기서 -1은 IMPOSSIBLE 을 의미합니다.
'알고리즘 > 알고리즘&자료구조 정리' 카테고리의 다른 글
문장의 가장 긴 단어 찾기. 자바 (0) | 2021.05.01 |
---|---|
알고리즘. 에라토스테네스의 체. 소수 구하기. 자바 (0) | 2021.04.25 |
피보나치 수열 출력. 알고리즘, 자바 (0) | 2021.04.25 |
해시테이블 자료구조 구현하기 (0) | 2021.03.28 |
최소 회수로 정렬하기(뒤집어 정렬하기), 정렬하는 회수 찾기 - 너비 우선 탐색 알고리즘 문제(Java 1.8) (0) | 2021.03.28 |
댓글
이 글 공유하기
다른 글
-
알고리즘. 에라토스테네스의 체. 소수 구하기. 자바
알고리즘. 에라토스테네스의 체. 소수 구하기. 자바
2021.04.25 -
피보나치 수열 출력. 알고리즘, 자바
피보나치 수열 출력. 알고리즘, 자바
2021.04.25 -
해시테이블 자료구조 구현하기
해시테이블 자료구조 구현하기
2021.03.28 -
최소 회수로 정렬하기(뒤집어 정렬하기), 정렬하는 회수 찾기 - 너비 우선 탐색 알고리즘 문제(Java 1.8)
최소 회수로 정렬하기(뒤집어 정렬하기), 정렬하는 회수 찾기 - 너비 우선 탐색 알고리즘 문제(Java 1.8)
2021.03.28