백준 17626번 : Four Squares

1. 문제

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

문제

라그랑주는 1770년에 모든 자연수는 넷 혹은 그 이하의 제곱수의 합으로 표현할 수 있다고 증명하였다. 어떤 자연수는 복수의 방법으로 표현된다. 예를 들면, 26은 52과 12의 합이다; 또한 42 + 32 + 12으로 표현할 수도 있다. 역사적으로 암산의 명수들에게 공통적으로 주어지는 문제가 바로 자연수를 넷 혹은 그 이하의 제곱수 합으로 나타내라는 것이었다. 1900년대 초반에 한 암산가가 15663 = 1252 + 62 + 12 + 12라는 해를 구하는데 8초가 걸렸다는 보고가 있다. 좀 더 어려운 문제에 대해서는 56초가 걸렸다: 11339 = 1052 + 152 + 82 + 52.

자연수 n이 주어질 때, n을 최소 개수의 제곱수 합으로 표현하는 컴퓨터 프로그램을 작성하시오.

입력

입력은 표준입력을 사용한다. 입력은 자연수 n을 포함하는 한 줄로 구성된다. 여기서, 1 ≤ n ≤ 50,000이다.

출력

출력은 표준출력을 사용한다. 합이 n과 같게 되는 제곱수들의 최소 개수를 한 줄에 출력한다.

 

예제 입력 1 복사

25

 

예제 출력 1 복사

1

예제 입력 2 복사

26

 

예제 출력 2 복사

2

예제 입력 3 복사

11339

 

예제 출력 3 복사

3

예제 입력 4 복사

34567

 

예제 출력 4 복사

4

2. 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		Integer n = Integer.parseInt(br.readLine());
		
		int[] dp = new int[n + 1];
		dp[0] = 0;
		dp[1] = 1;
		
		for (int i = 2; i <= n; i++) {
			dp[i] = i;
			int min = dp[i];
			for (int j = 0; j * j <= i; j++) {
				min = Math.min(min, dp[i - j * j]);
			}
			dp[i] = min + 1;
		}
		System.out.println(dp[n]);
	}

}

3. 해설

  • 동적 계획법으로 순차적으로 최소값을 정한다
  • dp[i] 값은 우선 최악의 경우로 1*1로만 이루어진 i 개로 초기화 하고
  • j * j 값을 뺀 값의 최소값에다 1을 더해서 찾는다
    → 예를 들어 dp[11] 이라면 dp[11 - 1] + 1, dp[11 - 4] + 1, dp[11 - 9] + 1에서 최소값을 찾는 개념

개선 할만 한점

  • 애초에 모든 수는 최대값이 4이므로 1,2,3 일 경우에 해당하는 지 확인함으로써 최소값을 찾을 수 있다.

4. 다른 풀이

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		Integer n = Integer.parseInt(br.readLine());
		int maxSqrt = (int) Math.sqrt(n);
		if (maxSqrt == Math.sqrt(n)) {
			System.out.println(1);
			return;
		}
		for (int i = 1; i <= maxSqrt; i++) {
			if ((int) Math.sqrt(n - i * i) == Math.sqrt(n - i * i)) {
				System.out.println(2);
				return;
			}
		}
		for (int i = 1; i <= maxSqrt; i++) {
			int currentMaxSqrt = (int) Math.sqrt(n - i * i);
			for (int j = 1; j <= currentMaxSqrt; j++) {
				if ((int) Math.sqrt(n - i * i - j * j) == Math.sqrt(n - i * i - j * j)) {
					System.out.println(3);
					return;
				}
			}
		}
		System.out.println(4);
	}

}
  • 첫번째 if 문
    • 해당 수가 제곱 수 인지 확인 후 맞으면 1 출력 후 종료
  • 첫번째 for문
    • i * i를 할당하여 n - i * i 값이 제곱 수 인지 확인 후 맞으면 2 출력 후 종료
    • 반복문의 조건은 최대로 대입할 수 있는 maxSqrt까지
  • 두번째 for문
    • 첫번째 for문에서 더 나아가 n - i * i - j * j 값이 제곱 수 인지 확인
    • 내부 for문의 조건은 n - i * i 의 최대 제곱근 까지

 

'Java > 알고리즘(코테)' 카테고리의 다른 글

백준 1260번 : DFS와 BFS  (1) 2024.10.02
백준 1012번 : 유기농 배추  (0) 2024.10.01
백준 27434번 : 팩토리얼 3  (0) 2024.09.25
백준 2579번 : 계단 오르기  (0) 2024.09.15
백준 1463번 : 1로 만들기  (1) 2024.09.14