중요 조건
N번째 계단을 밟는 방법?
1. n-3 → n-1 → n
2. n-2 → n위의 두 가지 경우만 존재하므로 점화식을 세우면
i번째 계단을 밟을 때 최고 점수(이하 scores[i]):
scores[i] = Math.max(scores[i-3]+stairs[i-1],scores[i-2])+stairs[i]
public static void main(String [] args) throws IOException {
BufferedReader br =
new BufferedReader(new InputStreamReader(System.in));
int count = Integer.parseInt(br.readLine());
int [] stairs = new int[count+1]; // 각 계단의 점수
int [] scores = new int[count+1]; // 현 계단까지 최고 점수
for(int i=1;i<=count;i++)
stairs[i] = Integer.parseInt(br.readLine());
...
count 변수에 계단의 개수를 입력 받고, stairs와 scores 배열을 선언한다.
데이터 입력 && 최고점 찾기
for(int i=1;i<=count;i++)
{
stairs[i] = Integer.parseInt(br.readLine());
}
scores[1] = stairs[1];
for(int i=2;i<=count;i++){
if(i==2)
scores[2] = stairs[1]+stairs[2];
else if(i==3)
scores[3] = Math.max(stairs[1],stairs[2])+stairs[3];
else
scores[i] = Math.max(scores[i-3]+stairs[i-1],scores[i-2])
+ stairs[i];
}
System.out.println(scores[count]);
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class N_2579 {
public static void main(String [] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int count = Integer.parseInt(br.readLine());
int [] stairs = new int[count+1]; // 각 계단의 점수 저장 배열
int [] scores = new int[count+1];
for(int i=1;i<=count;i++)
stairs[i] = Integer.parseInt(br.readLine());
scores[1] = stairs[1];
for(int i=2;i<=count;i++){
if(i==2)
scores[2] = stairs[1]+stairs[2];
else if(i==3)
scores[3] = Math.max(stairs[1],stairs[2])+stairs[3];
else
scores[i] = Math.max(scores[i-3]+stairs[i-1],scores[i-2]) + stairs[i];
}
System.out.println(scores[count]);
}
}
틀린 결과를 도출한 코드는 마지막 계단을 무조건 밟아야 한다는 조건에 집중해서 끝 계단에서 출발하여 처음 계단으로 가는 방법을 선택하여 아래와 같이 작성했다.
public class N_2579 {
public static void main(String [] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int total = 0; // 총 점수
int count = Integer.parseInt(br.readLine());
boolean check = false; // 연속된 3계단 감지
int [] stairs = new int[count]; // 각 계단의 점수 저장 배열
for(int i=0;i<count;i++)
stairs[i] = Integer.parseInt(br.readLine());
total += stairs[count-1]; // 마지막 계단 필수
int i;
// 계단 오르기 시작
for(i = count-1;i>=2;){
if(!check && stairs[i-1] > stairs[i-2]){
total+=stairs[i-1];
i=i-1;
check = true;
}
else{
total+=stairs[i-2];
i=i-2;
check=false;
}
}
if(!check) {
switch (i) {
case 1:
total += stairs[0];
break;
case 2:
total += stairs[0]<stairs[1]?stairs[1]:stairs[0];
break;
}
}
System.out.println(total);
}
}
- n-1과 n-2의 점수를 비교하여 더 큰 쪽으로 이동한다.
- n-1의 계단으로 이동한 경우는, 다시 n-1번째 계단으로 이동할 수 없으므로 check 변수를 사용해 연속으로 3계단을 오르지 못하도록 한다.
위 코드는 6, [40, 40, 20, 1, 20, 5]
케이스가 반례를 나타냈다.
작성한 코드의 결과값은 5+20+20+40 = 85 가 나오지만,
답은 40+40+1+5 = 86이므로 다른 방법을 생각해야했다.
런타임 에러 결과를 도출한 코드이다. 정답 코드에서 2, 3번째 값을 저장하는 코드를 for문 전에 작성했더니 발생했다.
scores[1] = stairs[1];
scores[2] = stairs[1]+stairs[2];
scores[3] = Math.max(stairs[1],stairs[2])+stairs[3];
for(int i=4;i<=count;i++)
scores[i] = Math.max(scores[i-3]+stairs[i-1],scores[i-2]) + stairs[i];
위 코드는 계단의 개수가 1개나 2개인 경우 scores[3]이나 stairs[3] 값이 당연히 존재할 수 없으므로 인덱스 범위 초과 에러가 발생한다.
부끄럽지만 처음 문제를 보고 DP를 떠올리지도 못했다. 하지만 이제 알아가면 되지!
문제를 풀고 모르면 빨리 찾아본 후, 이해하고 내 것으로 만드는 연습을 많이 해야겠다.
참고
yanghl98 / [백준] 2579 : 계단 오르기 (JAVA/자바)
girawhale / [백준] 2579번: 계단 오르기 - JAVA