Toolofv 님의 블로그

[Python] 백준 2629 - 양팔저울 본문

Algorithm

[Python] 백준 2629 - 양팔저울

Toolofv 2024. 6. 5. 10:48
반응형

 

문제

 

양팔 저울과 몇 개의 추가 주어졌을 때, 이를 이용하여 입력으로 주어진 구슬의 무게를 확인할 수 있는지를 결정하려고 한다.

무게가 각각 1g과 4g인 두 개의 추가 있을 경우, 주어진 구슬과 1g 추 하나를 양팔 저울의 양쪽에 각각 올려놓아 수평을 이루면 구슬의 무게는 1g이다. 또 다른 구슬이 4g인지를 확인하려면 1g 추 대신 4g 추를 올려놓으면 된다.

구슬이 3g인 경우 아래 <그림 1>과 같이 구슬과 추를 올려놓으면 양팔 저울이 수평을 이루게 된다. 따라서 각각 1g과 4g인 추가 하나씩 있을 경우 주어진 구슬이 3g인지도 확인해 볼 수 있다.

  

<그림 2>와 같은 방법을 사용하면 구슬이 5g인지도 확인할 수 있다. 구슬이 2g이면 주어진 추를 가지고는 확인할 수 없다.

추들의 무게와 확인할 구슬들의 무게가 입력되었을 때, 주어진 추만을 사용하여 구슬의 무게를 확인 할 수 있는지를 결정하는 프로그램을 작성하시오.

 

입력

첫째 줄에는 추의 개수가 자연수로 주어진다. 추의 개수는 30 이하이다. 둘째 줄에는 추의 무게들이 자연수로 가벼운 것부터 차례로 주어진다. 같은 무게의 추가 여러 개 있을 수도 있다. 추의 무게는 500g이하이며, 입력되는 무게들 사이에는 빈칸이 하나씩 있다. 세 번째 줄에는 무게를 확인하고자 하는 구슬들의 개수가 주어진다. 확인할 구슬의 개수는 7이하이다. 네 번째 줄에는 확인하고자 하는 구슬들의 무게가 자연수로 주어지며, 입력되는 무게들 사이에는 빈 칸이 하나씩 있다. 확인하고자 하는 구슬의 무게는 40,000보다 작거나 같은 자연수이다.

출력

 

주어진 각 구슬의 무게에 대하여 확인이 가능하면 Y, 아니면 N 을 차례로 출력한다. 출력은 한 개의 줄로 이루어지며, 각 구슬에 대한 답 사이에는 빈칸을 하나씩 둔다.

 

 

 

문제 해결 방법 - (서칭으로 참고후 해결)

 

 

1. 갖고 있는 추 리스트대로 dp를 구성한다. (행 인덱스는 '추의 갯수', 열 인덱스는  '구슬의 무게 - 추의 무게')이다. 재귀함수에 추의 갯수를 올려서 리턴하고 있고, 다음 추도 계속 올려야 할지 모르므로 1차원 DP는 짜기가 더 어렵다. 어떤 분기에서 DP에 이미 있는 무게면 다음 추를 올릴 수 없다.

 

2. l(왼쪽 저울), r(오른쪽 저울)을 만들고, 추의 리스트대로 idx를 증가시키며 각각 안 올릴 때, l에 올릴 때, r에 올릴 때의 분기를 가진 재귀함수를 만든다.  abs(l-r)의 값은 결국 잴 수 있는 구슬의 무게다.

 

-> 결과적이긴 하지만, abs(l-r)의 값이 구슬의 무게일 때, 잴 수 있다는 거다. 

     
위 예제를 참고한다면 l : 구슬의 무게(무게는 모른다.)측에 1g 올리고, r : 오른쪽 저울에 4g을 놓았을 경우, abs(l-r)는 3이고, 그 만큼의 구슬의 무게를 잴 수 있다는 뜻. 

 

1) 주어진 확인하고자 하는 구슬의 무게가 dp에 있으면 잴 수 있는 것이다.

 

3. 브루트포스 시 $O(3^{n})$의 시간복잡도를 가진다고 한다. dp로 먼저 계산된 값들은 제외시켜서 시간상 효율을 버는 것.

 

 

import sys
input = sys.stdin.readline

n = int(input())
d = list(map(int, input().split()))
m = int(input())
c = list(map(int, input().split()))
dp = [[0 for _ in range(15001)] for _ in range(n)]
ans = []

def sol(idx, l, r):
	t = abs(l-r)        # 잴 수 있는 구슬의 무게, 구슬의 처음무게는 이 함수에 올려놓지 않았다.
	if t not in ans:    # t의 값은 잴 수 있는 구슬의 무게다.
		ans.append(t)
	if idx == n:
		return 0
	if dp[idx][t] != 0: # 이미 dp에 기록된 잴 수 있는 구슬의 무게였다면 제외하는 것.
		return
	dp[idx][t] = 1
	sol(idx+1, l, r)
	sol(idx+1, l+d[idx], r)
	sol(idx+1, l, r+d[idx])

sol(0, 0, 0)
for i in c:
	if i in ans:
		print('Y')
	else:
		print('N')
반응형