티스토리 뷰
https://www.acmicpc.net/problem/2629
2629번: 양팔저울
첫째 줄에는 추의 개수가 자연수로 주어진다. 추의 개수는 30 이하이다. 둘째 줄에는 추의 무게들이 자연수로 가벼운 것부터 차례로 주어진다. 같은 무게의 추가 여러 개 있을 수도 있다. 추의 무
www.acmicpc.net
예전에 dfs로 완전탐색 했을 때는 시간초과가 났던 문제인데 dp를 공부한 후 다시 푸니까 풀려서 기분이 좋다^^
✔ 문제 조건
- 30개 이하의,
N
개의 추가 있으며, 각 추들의 무게는 500이하이다. 같은 무게의 추가 여러 개 있을 수 있다. 추의 무게를 담은 배열을balls[N+1]
라고 한다면,N
<=30,balls[i]
<= 500 - 무게를 확인할 구슬의 개수
M
은 7이하이며, 확인할 구슬의 무게는 40, 000보다 작거나 같은 자연수다. 확인할 구슬의 무게들을 담을 배열을target[M]
이라고 한다면,M
<=7,target[i]
<= 40, 000
✔ 접근 과정
- 무게가 1g인 추 하나만 있다면 1g만 확인 가능하다.
- 무게가 각각 1g인 추 뿐만 아니라 4g인 추도 있다면
- 각각의 무게인 1g과 4g은 확인 가능하다.
- 두 추의 무게의 차인 3g도 확인 가능하다.
- 두 추의 무게의 합인 5g도 확인 가능하다.
- 즉, i+1번째 추가 있다면
- i+1번째 추의 무게
balls[i+1]
g은 확인 가능하다. - 그 이전까지 확인 가능했던 무게
balls[i]
g 도 확인 가능할 것이다. (i+1번째 추를 사용하지 않는 경우랑 같다.) - 두 무게의 차인
abs(balls[i+1] - balls[i])
g과 합인abs(balls[i+1] + balls[i])
g도 확인 가능하다.
- i+1번째 추의 무게
- 따라서 boolean형 배열
dp[i][k]
이. i번째 추까지 살펴보았을 때k
g을 확인 가능한 경우라고 두었을 때dp[i-1][k]
가true
라면 ->dp[i][k]
,dp[i][i번째 추와 i-1추의 무게 차이]
,dp[i][i번째 추와 i-1추의 무게 합]
들은 모두true
가 된다.- 이렇게 해서 마지막 N번째 추까지 살펴보았을 때
dp[N][k]
가true
라면k
g은 확인 가능한 무게이다. - 추는 최대 30개가 있으며, 확인할 구슬의 무게는 최대 40,000이다. 따라서 dp배열은 최대
dp[30][40,000]
까지 선언될 수 잇다. 이때, 4 * 30 * 40, 000 = 48 * 10^5byte 까지의 메모리 공간을 필요로 하며 최대 메모리 제한은 128MB (128 * 10^6)이므로 메모리 초과가 나지 않는다.
import java.io.*;
import java.util.*;
// 210625
public class Main_BJ_2629_양팔저울 {
public static void main(String[] args) throws Exception {
//System.setIn(new FileInputStream("src/res/input.txt"));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = stoi(br.readLine()); // 구슬 개수
int[] balls = new int[N+1];
StringTokenizer st = new StringTokenizer(br.readLine(), " ");
for(int i=1; i<=N; i++) {
balls[i] = stoi(st.nextToken());
}
boolean[][] dp = new boolean[N+1][40001]; // 구슬 최대 무게 40,000
dp[1][balls[1]] = true;
for(int i=2; i<=N; i++) {
int w = balls[i]; // i번째 구슬까지 따졌을 때
dp[i][w] = true;
for(int k=1; k<=40000; k++) {
if(dp[i-1][k]) { // i-1번 구슬까지 따졌을 때 알 수 있는 무게라면
dp[i][k] = true;
int diff = Math.abs(w-k);
dp[i][diff] = true;
int plus = w+k;
if(plus>40000) continue;
dp[i][plus] = true;
}
}
}
int M = stoi(br.readLine()); // 무게 개수
st = new StringTokenizer(br.readLine(), " ");
for(int i=0; i<M; i++) {
int target = stoi(st.nextToken());
if(dp[N][target]) System.out.print("Y");
else System.out.print("N");
if(i!=(M-1)) System.out.print(" ");
}
br.close();
}
static int stoi(String str) {
return Integer.parseInt(str);
}
}
참고> dfs로 완전탐색하고 시간 초과가 났던 코드다.
코드를 보아하니,
1) 왼쪽에 추를 올릴 수 있는 모든 경우의 수를 구하면서
2) 왼쪽에 올리고 남은 추들을 오른쪽에 올릴 수 있는 모든 경우의 수들도 구해서
3) 왼쪽 추들의 무게와 오른쪽 추들의 무게의 합들의 차이만큼 측정 가능하다고 표시했다.
다시보니 정말 열심히 짜긴 했다..ㅋㅋ
'코딩테스트 > 백준' 카테고리의 다른 글
[BJ] 16918. 봄버맨 (0) | 2021.09.14 |
---|---|
[BJ] 1238. 파티 (0) | 2021.06.25 |
[BJ] 1932. 정수 삼각형 (0) | 2021.06.06 |
[BJ] 17472. 다리 만들기 2 (0) | 2021.04.24 |
[BJ] 20057. 마법사 상어와 토네이도 (0) | 2021.04.24 |
댓글