-
[Algorithm] 백준/Silver/9461. 파도반 수열 (반복문, 재귀함수)Algorithm/문제 풀이 2023. 4. 3. 10:06
하루입니다.
https://www.acmicpc.net/problem/9461
9461번: 파도반 수열
오른쪽 그림과 같이 삼각형이 나선 모양으로 놓여져 있다. 첫 삼각형은 정삼각형으로 변의 길이는 1이다. 그 다음에는 다음과 같은 과정으로 정삼각형을 계속 추가한다. 나선에서 가장 긴 변의
www.acmicpc.net
오늘의 문제는 파도반 수열. 이름이 예쁘다.
실버 3짜리 문제지만, ssafy 준비할 때 풀었던 기억이 있어서 도전했다.

문제점 : 아무리 봐도 내 점화식이 맞는데 자꾸 틀렸다고 함. 디버깅 돌렸는데도 도대체 틀린 게 뭔지 모르겠음. 질문게시판 찾아감. 보통 1. 배열 크기 잘못 설정 2. 값이 잘못 들어감 두 가지 원인 때문이었음. 나는 점화식이 맞으니까 값이 틀릴 리 없겠지! 라는 생각을 했는데, 사실 점화식 문제가 아닌 데이터타입 문제였음. 일정 숫자가 넘어가면 int의 범위를 넘어서 오버플로우가 발생하고, 값이 -로 변경되며 이상한 값을 출력하게 되어서 그런 거였다.
오버플로우가 되었는데 -가 되는 이유 : 자바의 int 타입은 4바이트의 크기를 가지며, 부호 비트를 포함하여 최대 2^31 - 1까지의 값을 표현할 수 있습니다. 따라서 int 변수에 저장된 값이 이 범위를 초과하면 오버플로우(overflow)가 발생합니다.
예를 들어, int 타입의 최대값인 2^31 - 1을 가지는 변수에 1을 더하면, 값은 -2^31이 됩니다. 이는 부호 비트가 1이 되면서 양수에서 음수로 바뀌고, 나머지 비트들이 0에서 1로 바뀌기 때문입니다.

고민의 흔적 해결 : 배열을 long으로 선언 후 사용했음.
의문 : 이런 문제는 처음부터 long으로 선언하는 게 맞나? 아니면 한 번 틀리고 아 오버플로우 문제구나 하고 고치는 게 맞나? 처음부터 예상하고 시작하는 건가?

코드 보기
더보기import java.util.*;
import java.io.*;
class Main {
public static void main(String args[]) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int t = Integer.parseInt(br.readLine());
long dp[] = new long[101];
dp[1] = 1;
dp[2] = 1;
dp[3] = 1;
for(int i = 0; i < t; i++) {
int n = Integer.parseInt(br.readLine());
for(int j = 4; j <= n; j++) {
dp[j] = dp[j-2] + dp[j-3];
}
System.out.println(dp[n]);
}
}
}
다른 해결법 : 재귀함수 사용
일단 ... 재귀함수를 배우긴 했으나 어떻게 작동하는지 잘 모르겠음. 그래도 디버깅 하면서 어떤 식으로 동작하는지 조금은 알게 되었다.
최대 dp[100]까지 가능하기에 101칸을 생성해야 한다(0은 안 쓰니까). for문을 사용해서 dp[1] ~ dp[100]까지 값을 넣고 바로바로 뽑아쓰는 방법도 가능하나, 만약 3 1 4 3 이런 식으로 주어지면 최대 배열 4까지만 사용하므로 나머지는 모두 필요가 없어진다. 메모리 낭비.

내가 참고한 분은 입력받은 숫자 부분이 dp[]에 없을 때(int라면 0, Integer라면 null일 때) 돌아가는 재귀함수를 생성하셨다.
class 전체에서 사용하기 위해선 static 변수로 선언해야 함을 기억하자. 디버깅 돌리니까 처음부터 배열이 생성되어 있는 거 보고 신기했다.

그럼에도 헷갈려서 직접 돌려본 결과를 들고 왔다. 아마 이게 재귀함수가 실행되는 순서일 거고, 스택에 쌓였다가 선입선출된다는 뜻이겠지? 빨간색은 return 되는 경우이다. 계속해서 n - (n-2) - 없다면 다시 (n-2) - 있다면 return - 다시 8로 갔다가 이번엔 n-3 ... 으로 반복되는 것을 알 수 있다.

코드 보기
더보기import java.util.*;
import java.io.*;
class Main {
// 클래스 전역에서 사용하기 위해 static 배열을 선언한다.
// 클래스 변수는 전역 변수의 일종이지만, 반드시 전역 변수가 클래스 변수인 것은 아닙니다.
public static long dp[] = new long[101];
public static void main(String args[]) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
dp[0] = 0;
dp[1] = 1;
dp[2] = 1;
dp[3] = 1;
int t = Integer.parseInt(br.readLine());
while(t-- > 0) {.
sb.append(pado(Integer.parseInt(br.readLine()))).append('\n');
}
System.out.println(sb);
}
public static long pado(int n) {
if(dp[n] == 0) {
dp[n] = pado(n - 2) + pado(n - 3);
}
return dp[n];
}
}
이야
어렵다!
하지만 최근 푼 문제 중에 젤 재밌었다.
주석 있는 코드가 궁금하시다면
오늘도 감사합니다!
https://st-lab.tistory.com/127
'Algorithm > 문제 풀이' 카테고리의 다른 글
[Algorithm] 백준/Bronze/2525. 오븐 시계 (바보) (2) 2023.04.05 [Algorithm] 백준/Silver/2193. 이친수 (0) 2023.04.03 [Algorithm] 백준/Silver/10773. 제로 (Stack) (2) 2023.04.02 [ Algorithm ] 백준/Bronze/10813. 공 바꾸기 (바보비용) (0) 2023.04.01 1231. [S/W 문제해결 기본] 9일차 - 중위순회 (0) 2023.03.30