[Python] 1로 만들기 - DP

Saemi Min·2023년 2월 3일
0

BaekJoon

목록 보기
3/30
post-thumbnail


해당 문제 링크

풀이

n=int(input())
dp=[0] *(n+1)
for i in range(2, n+1):
    dp[i]=dp[i-1]+1
    if i%3==0:
        dp[i]=min(dp[i], dp[i//3] +1 ) 
    if i%2==0:
        dp[i]=min(dp[i], dp[i//2] +1 )
print(dp[n])

Git - 코드

해석

DP를 공부하고 처음 관련 문제를 풀어보고자 했던 문제인데 작은 값들이 반복적으로 쓰인다는 느낌은 왔지만 코드로는 잘 안짜져서 답답했다..다른 사람들의 코드를 참고한 뒤 코드 이해 후 나도 쉽게 짜지는 그날까지..열심히 하고자 한다.
이 문제는 DP의 하향식으로 작성하는게 더 간단하다.
코드를 해석해보면
처음 값을 받고, 소문제 결과를 저장할 리스트, 즉 2일때 최소 연산 횟수, 3일때 최소 연산 횟수를 저장할 리스트를 만든다 (= 메모이제이션 할 리스트)

n=int(input())
dp=[0] * (n+1) 
#n+1을 한 이유는 dp[1]은 첫번째 수로, dp[2]는 두번째 수로 생각하기 위해서 이다. (계산하기 편함을 위해서)

for문을 통해 2부터 n 값까지 배열에 횟수를 넣어준다. 즉 2일 때의 최소 연산 횟수 계산해주고, n일 때의 최소 연산 횟수까지 계산해주어야지 값이 나오기 때문이다.
=> 아래에서부터 계산을 수행하고 누적시켜서 전체 큰 문제를 해결하기 위해 for문을 사용한다.

문제에서

  • (1을 빼는 방법)
  • (2를 나누는 방법)
  • (3을 나누는 방법)
    중에서 가장 최소 연산 횟수가 무엇인지를 고려해야 한다

무조건 나눈다고 최소 연산 횟수는 아니다.
ex) 10의 최소 연산 횟수를 구하고자 할 때
나누는 방법을 우선시 했을 경우, 10-5-4-2-1 으로 4번이나 연산 횟수가 일어나야한다.
하지만 처음 10에서 1을 빼면 10-9-3-1로 3번의 연산 횟수가 일어난다. 즉 3이 출력되어야 한다는 것이다.

이 문제가 DP인 이유는

  • 2-1 (1)
  • 3-1 (1)
  • 4-2-1 (2)
  • 5-4-2-1 (3)
  • 6-3-1 / 6-2-1 (2)
  • 7-6-3-1 / 7-6-2-1 (3)
    ...
    와 같이 작은 소문제가 반복되기 때문이다.
    dp 배열에는 (0, 0, 1, 1, 2, 3, 2, 3, ..) 이렇게 들어간다.

for문 안 코드를 살펴보면

	dp[i]=dp[i-1]+1
    if i%3==0:
        dp[i]=min(dp[i], dp[i//3] +1 ) 
    if i%2==0:
        dp[i]=min(dp[i], dp[i//2] +1 )

이렇게 되어있다.

dp[i]=dp[i-1]+1 의 경우에 dp[i-1]가 앞서 계산된 최소연산 횟수인데 앞선 수에 대한 연산횟수에 (앞서 말한, 1을 빼는 방법)을 했다고 생각해서 1번의 연산이 일어난 것이기 때문에 +1을 더한 것이다. 무작정 1을 빼는 방법을 먼저 수행해놓고 본것이다! 이후에 이 방법이 작은 경우의 수를 만들게 한 것인지는 min()함수를 써서 비교할 것이기 때문이다!

if문으로 3으로 나누어 떨어지는지 2로 나누어떨어지는 지를 본다. 이때 if/elif/else 방법을 쓰면 안된다.
3으로 나누어 진다면, (1을 빼는 방법)이 더 적은연산횟수를 갖게 된것인지, (3을 나누는 방법)이 더 적은연산횟수를 갖게 된것인지를 비교해서 더 작은 방법을 갖게 된다!
여기에서도 dp[i//3] + 1에 1을 더하는 이유는 (2를 나누는 방법)을 써서 추가되는 연산횟수이다. 이전에 (1을 빼는 방법)을 써서 발생한 연산횟수에 대해 더해주는 것과 같은 느낌이다!!

ex) 6일 때를 계산해보자

dp[6]=dp[5]+1 //3+1 => dp[6]=4 #(1을 빼는 방법)
if(i%3)==0: 
	dp[i]=min(dp[i], dp[i//3] +1 ) //min(4, 1+1) => dp[6]=2
    => 4에서 2로 더 작은 연산 횟수로 바뀐 것을 볼 수 있음

코드는 이런 구조로 돌아가 결과를 출력할 수 있다.
참고 코드

DP 문제 더 풀어서 감 잡아야겠다!! 아직까지는 어렵다는 생각이 든다..ㅠ

profile
I believe in myself.

0개의 댓글