본문 바로가기

백준

백준1699 - 제곱수의 합

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

 

1699번: 제곱수의 합

어떤 자연수 N은 그보다 작거나 같은 제곱수들의 합으로 나타낼 수 있다. 예를 들어 11=32+12+12(3개 항)이다. 이런 표현방법은 여러 가지가 될 수 있는데, 11의 경우 11=22+22+12+12+12(5개 항)도 가능하다. 이 경우, 수학자 숌크라테스는 “11은 3개 항의 제곱수 합으로 표현할 수 있다.”라고 말한다. 또한 11은 그보다 적은 항의 제곱수 합으로 표현할 수 없으므로, 11을 그 합으로써 표현할 수 있는 제곱수 항의 최소 개수는

www.acmicpc.net

점화식 문제다. 각각의 제곱수를 최소 갯수로 더하여 내가 찾는 수가 나오도록 하면 된다.

 

ex1.) 20, 루트 20은 4.xxxxxxx니까 최대 4의 제곱까지만 더한다.

1의 제곱 + 19를 만드는데 필요한 수의 갯수(1, 3, 3) : 1 + 3 = 4

2의 제곱 + 16을 만드는데 필요한 수의 갯수(4) : 1 + 1 = 2

3의 제곱 + 11을 만드는데 필요한 수의 갯수(1, 1, 3) : 1 + 3 = 4

4의 제곱 + 4를 만드는데 필요한 수의 갯수(2) : 1 + 1 = 2

20은 최소 2개로 만들 수 있다.

 

ex2.)12, 루트 12는 3.xxxxxx니까 최대 3의 제곱까지만 더한다.

1의 제곱 + 11을 만드는데 필요한 수의 갯수(1, 1, 3) : 1 + 3 = 4

2의 제곱 + 8을 만드는데 필요한 수의 갯수(2, 2) : 1 + 2 = 3

3의 제곱 + 3을 만드는데 필요한 수의 갯수(1, 1, 1) : 1 + 3 = 4

12는 최소 3개로 만들 수 있다.

 

다음과 같은 과정을 이중 포문을 돌려 완성한다.

 

#include <iostream>
#include <cmath>
using namespace std;

int mat[100001]; //10만개 수에 대한 DP결과값을 찾는다.

int main() {
	int what; //찾는 수를 입력
	int check; //제곱하였을 때 10만에 가장 가까운 수가 무엇인지 찾는다.

	cin >> what; //찾는 수 입력

	check = sqrt(100000); //10만까지 자연수 중 제곱하였을 때 가장 10만에 가장 가까운 수를 찾는다.

	//10만 범위 중 오직 하나의 자연수의 제곱만으로 만들어지는 수를 1로 초기화한다.
	for (int i = 1; i <= check; i++) {
		mat[i * i] = 1;
	}

	//DP를 이용하여 각 구현
	for (int i = 1; i <= what; i++) {
		for (int j = 1; j <= int(sqrt(i)); j++) {
			if (!mat[i] || mat[i] > mat[i - j * j] + mat[j * j]) { //DP값이 없는 곳이나 구해진 DP값보다 현재 수를 이용하여 구한 DP값이 작으면
				mat[i] = mat[i - j * j] + mat[j * j]; //DP값 갱신
			}
		}
	}

	cout << mat[what]; //내가 찾는 수의 DP결과를 출력
}

'백준' 카테고리의 다른 글

백준17214 - 다항 함수의 적분  (0) 2019.07.30
백준4889 - 안정적인 문자열  (0) 2019.07.30
백준2606 - 바이러스  (0) 2019.07.28
백준15739 - 매직스퀘어  (0) 2019.07.26
백준1773 - 폭죽쇼  (0) 2019.07.26