Knapsack
09 May 2019HackerRank link
주어진 배열로 목표 합을 배열의 원소를 0번 또는 여러번 사용하여 넘치지 않고 가장 근접한 합을 만들어 리턴!!
ex) arr=[2,3,4] target sum = 10 인경우
[2,2,2,2,2] , [2,2,3,3], 등..
input
t
n k
배열 원소들
t : test case 수
n : 배열 사이즈
k : 목표 합
제약조건
1 <= t <= 10
1 <= n,k,arr[i] <= 2000
풀이 과정
먼저 심플하게 생각해 보면 모든 경우의 수를 다 해보면 풀릴 것 같다.
또한, 예시 입력을 봤을 때에도 arr[i]의 각 원소는 중복 될 수 있다.
모든 경우의 수를 다 해보면 비 효율적이므로,
첫 번째로 할만한 경우는 더하지 않고 가능한 경우이다.
어떤 수를 나눈 나머지가 0 인경우 더해볼 필요가 없다. 그럼 어떻게 나눠야 할까?
소수 구하는 방법처럼 2, 3의 곱들을 제거 해 보았다.
또한 2+3 = 5의 경우도 만들어질 수 있으므로, 제거해 보았다.
그런데 23같은 경우 2x10+3이므로 23도 지워져야 된다. 따라서, 곱셈만으로는 구하기 어려워 보인다.
이 때문에 효율적으로 모든 경우의 수를 더하여 체크한는 방법을 생각해 보았다.
재귀적으로 현재 수에서 배열의 수를 순차적으로 더하는 방법이 가능하다.
그런데, 제약 조건을 봤을 때, n,k,arr[i]이 2000이다. 사이즈가 굉장히 적다.
사이즈가 굉장히 적기 때문에, flag를 두어서 이미 체크한 경우를 생각할 수있다.
그래서 중복으로 함수를 call 할필요 없게 만들 수 있다.
또한, 입력의 중복된 원소를 제거하기 위해 오름차순으로 정렬을 한다음 중복되는 수는 제거해 준다.
풀이 핵심
- 제약조건이 낮기 때문에, 심플하게 재귀적으로 모든 수를 더하여 체크할 수 있다.
- 제약조건이 낮기 때문에, flag를 두어 중복 체크를 방지 가능
Algorithm
- 입력받은 수를 오름차순으로 정렬한다.
- 중복된 입력은 제거 한다.
- 재귀적으로 0부터 입력을 모두 더하여 체크 한다.
Source Code
import java.io.*;
import java.math.*;
import java.security.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.*;
public class Solution {
// Complete the unboundedKnapsack function below.
static final int maxInput = 2000;
static int checkMax = 0;
static void check(boolean[] isChecked, ArrayList<Integer> al, int cur, int target) {
if(cur > target || cur > isChecked.length) return;
if(isChecked[cur]) {
return;
}
isChecked[cur] = true;
if(checkMax < cur ) checkMax = cur;
for(int e : al) {
check(isChecked, al, cur+e, target);
}
}
static int unboundedKnapsack(int k, int[] arr) {
ArrayList<Integer> al = new ArrayList<>();
boolean[] isChecked = new boolean[maxInput +1];
checkMax = 0;
Arrays.sort(arr);
int i = 0;
int before = 0;
for(int e : arr) {
if(before == e) {
continue;
}
al.add(e);
before = e;
}
check(isChecked, al, 0,k);
return checkMax;
}
private static final Scanner scanner = new Scanner(System.in);
public static void main(String[] args) throws IOException {
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));
int t = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
for(int test = 0; test < t; test++) {
String[] nk = scanner.nextLine().split(" ");
int n = Integer.parseInt(nk[0]);
int k = Integer.parseInt(nk[1]);
int[] arr = new int[n];
String[] arrItems = scanner.nextLine().split(" ");
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
for (int i = 0; i < n; i++) {
int arrItem = Integer.parseInt(arrItems[i]);
arr[i] = arrItem;
}
int result = unboundedKnapsack(k, arr);
System.out.println(result);
bufferedWriter.write(String.valueOf(result));
bufferedWriter.newLine();
}
bufferedWriter.close();
scanner.close();
}
}