https://www.acmicpc.net/problem/2629
2629번: 양팔저울
첫째 줄에는 추의 개수가 자연수로 주어진다. 추의 개수는 30 이하이다. 둘째 줄에는 추의 무게들이 자연수로 가벼운 것부터 차례로 주어진다. 같은 무게의 추가 여러 개 있을 수도 있다. 추의 무
www.acmicpc.net
코드설명
DP(Dynamic Programming) + 냅색(Knapsack, 배낭문제) 문제 입니다.
이 문제에서 DP[31][30*500 + 1] 은 구슬의 개수가 30개를 사용했을때 15001 개의 배열 중에서 결론적으로 잴 수 있는 무게인지 아닌지의 참/거짓이 저장됩니다.
문제에서 무게를 잴 구슬을 항상 양팔 저울 중에서 왼쪽 저울에 둔다고 가정해보겠습니다.
DFS(level + 1, weight + arr[level]) : 오른쪽저울에 추를 둡니다.
DFS(level + 1, weight); : 오른쪽 저울에 아무것도 두지 않습니다.
DFS(level + 1, Math.abs(weight - arr[level])); : 왼쪽 저울에 추를 올립니다.
위와 같이 진행하면 DP[N][15001] 의 N번쨰 배열은 결국 모든 무게의 가능여부를 확인할 수 있습니다.
if(dp[N][K] == true)
위와 같이 잴 수 있는 구슬의 무게를 구할때 DP[N][~] 에서 N번째 배열을 확인하는 이유는 N번째에 모든 경우를 다 탐색하는것이기 때문입니다. 그전에도 for문으로 DP의 모든 경우를 돌면서 가능한 경우가 하나라도 있다면 하는방법으로 체크해도 되지만 그렇게 할경우 시간복잡도로 시간초과가 날 것 입니다.
문제에서 유의해야할점은, 최대 추의 개수는 30 이하이고, 추의 무게는 500g 이하이기 떄문에 최대 추로 잴 수 있는 무게는 30 * 500 으로 15000 입니다.
하지만, 확인하고자하는 구슬의 무게는 40,000 보다 작거나 같기에 dp[N][30 * 500 + 1] 로 해놓았기에 런타임 에러 (ArrayIndexOutOfBounds) 가 발생하는데, 아래와 같이 continue 구문을 추가하거나 if esle if else if 로 처리하여 초과된 구슬의 무게일경우 로직이 검증하지 않도록 처리해줍니다.
for(int i=0;i<M;i++) { int inputMarbleWeight = Integer.parseInt(st.nextToken()); if(inputMarbleWeight > 15000) { System.out.print("N "); continue; } if(dp[N][inputMarbleWeight] == true) { System.out.print("Y "); }else { System.out.print("N "); } }
코드
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.LinkedList; import java.util.Queue; import java.util.StringTokenizer; public class Main { public static int N, M; public static int answer = 0; public static int[] arr = new int[31]; public static boolean[][] dp = new boolean[31][30*500 + 1]; public static StringBuilder sb = new StringBuilder(); public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); st = new StringTokenizer(br.readLine()); for(int i=0;i<N;i++) { arr[i] = Integer.parseInt(st.nextToken()); } //여기서 미리 DP로 가능한 경우의 모든 수를 구한다. DFS(0, 0); st = new StringTokenizer(br.readLine()); M = Integer.parseInt(st.nextToken()); st = new StringTokenizer(br.readLine()); for(int j=0;j<M;j++) { int K = Integer.parseInt(st.nextToken()); if(K > 15000) sb.append("N "); else if(dp[N][K] == true) { sb.append("Y "); }else { sb.append("N "); } } System.out.println(sb.toString()); } public static void DFS(int level, int weight) { if(dp[level][weight] == true) return ; dp[level][weight] = true; if(level == N) return ; DFS(level + 1, weight + arr[level]); DFS(level + 1, weight); DFS(level + 1, Math.abs(weight - arr[level])); } }
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.StringTokenizer; public class Main { public static int N, M; public static Marble[] marble; public static boolean[][] dp; public static int answer = 0; public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); marble = new Marble[31]; dp = new boolean[31][30 * 500 + 1]; st = new StringTokenizer(br.readLine()); for(int i=0;i<N;i++) { int inputMarbleWeight = Integer.parseInt(st.nextToken()); marble[i] = new Marble(inputMarbleWeight); } simulate(0,0); st = new StringTokenizer(br.readLine()); M = Integer.parseInt(st.nextToken()); st = new StringTokenizer(br.readLine()); for(int i=0;i<M;i++) { int inputMarbleWeight = Integer.parseInt(st.nextToken()); if(inputMarbleWeight > 15000) { System.out.print("N "); continue; } if(dp[N][inputMarbleWeight] == true) { System.out.print("Y "); }else { System.out.print("N "); } } } public static void simulate(int level, int weight) { if(dp[level][weight] == true) return ; dp[level][weight] = true; if(level >= N) return ; simulate(level + 1, weight + marble[level].weight); simulate(level + 1, weight); simulate(level + 1, Math.abs(weight - marble[level].weight)); } } class Marble{ int weight; public Marble(int weight) { this.weight = weight; } }