어떤 자연수 N은 그보다 작거나 같은 제곱수들의 합으로 나타낼 수 있다. 예를 들어 11=32+12+12(3개 항)이다. 이런 표현방법은 여러 가지가 될 수 있는데, 11의 경우 11=22+22+12+12+12(5개 항)도 가능하다. 이 경우, 수학자 숌크라테스는 “11은 3개 항의 제곱수 합으로 표현할 수 있다.”라고 말한다. 또한 11은 그보다 적은 항의 제곱수 합으로 표현할 수 없으므로, 11을 그 합으로써 표현할 수 있는 제곱수 항의 최소 개수는 3이다.
주어진 자연수 N을 이렇게 제곱수들의 합으로 표현할 때에 그 항의 최소개수를 구하는 프로그램을 작성하시오.
// 나의 오답 functionLBS(arr) { const N = arr.length; constDP = Array.from({ length: N }, () =>1);
for (let i = 1; i < N; i++) { for (let j = 0; j < i; j++) { if (A[j] < A[i]) { DP[i] = Math.max(DP[i], DP[j] + 1); } } for (let k = i + 1; k < N; k++) { if (A[k] >= A[k - 1]) break;
DP[i] = Math.max(DP[i], DP[i] + 1); } }
returnMath.max(...DP.map((elem) => elem - 1)); }
console.log(LBS(A));
처음에는 감소하는 부분 수열을 구할 때, 역순으로 시작하지 않고 증가하는 부분 수열 구할 때 새로운 반복문으로 해당 index부터 시작하는 감소하는 부분 수열을 구하였는데 이는 DP라는 배열 하나를 가지고 반복문을 돌렸기 때문에 제대로 동작하지 않고 저장값이 꼬여버릴 수 있다.
처음에는 1번째 집이 R,G,B를 선택하는 경우의 수를 구하고 이를 이 중 가장 작은 것을 가지고 다음 집을 구한다고 생각했다. 생각은 했는데 이를 코드로 어떻게 짜야할지 생각을 못해서 경우의수를 일일히 적어보고 패턴을 찾아보려고 했다.
하지만 못찾아서 다른 사람의 해설을 참고하였다. 문제가 복잡해보이지만 단순하게 생각하면 인접한 집끼리는 같은 색상을 가질 수 없다는 것이 전부이다.
우선, DP 배열을 만들고 해당 DP[i][0]은 i번째 집을 Red로 색칠하는 비용을 저장한다.
DP[1] = input[0] 이 성립한다.
이후 i = 2 부터 반복문을 진행한다.
DP[2]가 R로 색칠될 경우의 비용을 저장한다. ⇒ DP[2]가 R 이기 위해서는 DP[1]에서 G, B로 색칠되어야만 가능하다. 즉 DP[1]에서 G, B를 칠하는 비용 중 최소값을 구하고 이에 input의 2번째 집에 해당하는 비용 중 R을 색칠하는 비용을 더해주면 DP[2][0] 즉, 2번째 집을 R로 칠할 때 최소 비용을 구할 수 있다.
DP[2][1]은 이전 집에서 R, B 중 최소값에다가 input의 2번째 집에 해당하는 비용 중 G을 색칠하는 비용을 더해주면 DP[2][1]의 최솟값을 구할 수 있다.