카테고리 없음

BOJ 1699: 제곱수의 합

무니화니 2022. 1. 3. 23:16

오늘도 다이내믹 프로그래밍 문제를 풀고 있다. 

풀다 보니까, 이것도 다이내믹 프로그래밍이야? 라고 생각 하게 만드는 문제들도 정말 많다.

이 문제가 바로 이와 같은 경우다.


https://www.acmicpc.net/problem/1699

 

1699번: 제곱수의 합

어떤 자연수 N은 그보다 작거나 같은 제곱수들의 합으로 나타낼 수 있다. 예를 들어 11=32+12+12(3개 항)이다. 이런 표현방법은 여러 가지가 될 수 있는데, 11의 경우 11=22+22+12+12+12(5개 항)도 가능하다

www.acmicpc.net

 


처음에 풀었던 내 잘못된 풀이이다.

n이라는 수가 주어지고, 그 수보다 작은 제곱수를 빼면 된다고 생각을 했었다.

from math import *
n=int(input())
result=0
while n>0:
  root=int(floor(sqrt(n)))
  n-=root**2
  result+=1
print(result)

그러나 이 방법으로 풀면, 20000같은 수가 제시되었을 때, 20000보다 작은 제곱수를 빼야 하지만, 그렇게 빼는 것 보다 100의 제곱인 10000을 두번 더하는 것이 더 빠르다.

결국 오답이다.


그렇기에 고민 끝에 다른 블로그를 참고했다.

n=int(input())
dp=[i for i in range(n+1)]
for i in range(1,n+1):
  for j in range(1,i):
    if j*j>i:
      break
    if dp[i]>dp[i-j*j]+1:
      dp[i]=dp[i-j*j]+1
print(dp[n])

단순하지만, 강력하다.

반복문을 돌면서, 주어진 수 n보다 작은 모든 제곱수에 대해서 빠진 수를 돌면서, dp를 업데이트한다.

 

예를 들자.

13이라면, 

원래 dp[4]=4였을 것이다.

그러나 i가 4일때 j=2면, 

dp[4]=dp[4-2*2]+1에 딱 맞아 떨어질 것이다.

dp[4]=1+1=2가 들어간다.

이런식으로 모든 index의 최솟값을 구해본다..!


아직 다이내믹 프로그래밍 문제를 식별하는 것도, 기본 점화식을 만들어 내는 것도 참 어렵다.

그렇지만, 더욱 열심히 화이팅!