www.acmicpc.net/problem/2751

 

2751번: 수 정렬하기 2

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄부터 N개의 줄에는 숫자가 주어진다. 이 수는 절댓값이 1,000,000보다 작거나 같은 정수이다. 수는 중복되지 않는다.

www.acmicpc.net

문제

N개의 수가 주어졌을 때, 이를 오름차순으로 정렬하는 프로그램을 작성하시오.

입력

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄부터 N개의 줄에는 숫자가 주어진다. 이 수는 절댓값이 1,000,000보다 작거나 같은 정수이다. 수는 중복되지 않는다.

출력

첫째 줄부터 N개의 줄에 오름차순으로 정렬한 결과를 한 줄에 하나씩 출력한다.

예제 입력 1

5

5

4

3

2

1

예제 출력 1

1

2

3

4

5

 

 

 

 

 

풀이 .

import java.io.*;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringBuilder sb = new StringBuilder();
        int n = Integer.parseInt(br.readLine());
        int[] arr = new int[n];
        for(int i = 0; i < n; i++) {
            arr[i] = Integer.parseInt(br.readLine());
        }

        Arrays.sort(arr);
        for(int ans : arr) {
            sb.append(ans).append("\n");
        }
        bw.write(sb.toString());

        br.close();
        bw.flush();
        bw.close();
    }
}

 

내장 정렬함수를 사용하면 된다.

 

n의 최대값은 백만이지만 Arrays.sort()로 해결이 가능하다.

(이 정렬은 원시 타입에 대하여 dual pivot quicksort를 사용한다. 일반 퀵정렬이 최대 O(n^2)까지 갈 수 있다는 점을 보완한 알고리즘이다.)

 

출력을 n줄로 해야하기 때문에 System.out.println()을 쓰면 시간초과가 발생한다.

입출력에 주의하자.

www.acmicpc.net/problem/11052

 

11052번: 카드 구매하기

첫째 줄에 민규가 구매하려고 하는 카드의 개수 N이 주어진다. (1 ≤ N ≤ 1,000) 둘째 줄에는 Pi가 P1부터 PN까지 순서대로 주어진다. (1 ≤ Pi ≤ 10,000)

www.acmicpc.net

문제

요즘 민규네 동네에서는 스타트링크에서 만든 PS카드를 모으는 것이 유행이다.

PS카드는 PS(Problem Solving)분야에서 유명한 사람들의 아이디와 얼굴이 적혀있는 카드이다. 각각의 카드에는 등급을 나타내는 색이 칠해져 있고, 다음과 같이 8가지가 있다.

  • 설카드
  • 레드카드
  • 오렌지카드
  • 퍼플카드
  • 블루카드
  • 청록카드
  • 그린카드
  • 그레이카드

카드는 카드팩의 형태로만 구매할 수 있고, 카드팩의 종류는 카드 1개가 포함된 카드팩, 카드 2개가 포함된 카드팩, ... 카드 N개가 포함된 카드팩과 같이 총 N가지가 존재한다.

민규는 카드의 개수가 적은 팩이더라도 가격이 비싸면 높은 등급의 카드가 많이 들어있을 것이라는 미신을 믿고 있다. 따라서, 민규는 돈을 최대한 많이 지불해서 카드 N개 구매하려고 한다. 카드가 i개 포함된 카드팩의 가격은 Pi원이다.

예를 들어, 카드팩이 총 4가지 종류가 있고, P1 = 1, P2 = 5, P3 = 6, P4 = 7인 경우에 민규가 카드 4개를 갖기 위해 지불해야 하는 금액의 최댓값은 10원이다. 2개 들어있는 카드팩을 2번 사면 된다.

P1 = 5, P2 = 2, P3 = 8, P4 = 10인 경우에는 카드가 1개 들어있는 카드팩을 4번 사면 20원이고, 이 경우가 민규가 지불해야 하는 금액의 최댓값이다.

마지막으로, P1 = 3, P2 = 5, P3 = 15, P4 = 16인 경우에는 3개 들어있는 카드팩과 1개 들어있는 카드팩을 구매해 18원을 지불하는 것이 최댓값이다.

카드 팩의 가격이 주어졌을 때, N개의 카드를 구매하기 위해 민규가 지불해야 하는 금액의 최댓값을 구하는 프로그램을 작성하시오. N개보다 많은 개수의 카드를 산 다음, 나머지 카드를 버려서 N개를 만드는 것은 불가능하다. 즉, 구매한 카드팩에 포함되어 있는 카드 개수의 합은 N과 같아야 한다.

입력

첫째 줄에 민규가 구매하려고 하는 카드의 개수 N이 주어진다. (1 ≤ N ≤ 1,000)

둘째 줄에는 Pi가 P1부터 PN까지 순서대로 주어진다. (1 ≤ Pi ≤ 10,000)

출력

첫째 줄에 민규가 카드 N개를 갖기 위해 지불해야 하는 금액의 최댓값을 출력한다.

예제 입력 1

4

1 5 6 7

예제 출력 1

10

예제 입력 2

5

10 9 8 7 6

예제 출력 2

50

예제 입력 3

10

1 1 2 3 5 8 13 21 34 55

예제 출력 3

55

예제 입력 4

10

5 10 11 12 13 30 35 40 45 47

예제 출력 4

50

예제 입력 5

4

5 2 8 10

예제 출력 5

20

예제 입력 6

4

3 5 15 16

예제 출력 6

18

 

 

 

 

 

 

풀이 .

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

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());

        int[] dp = new int[n + 1];
        int[] p = new int[n + 1];
        StringTokenizer st = new StringTokenizer(br.readLine());
        for(int i = 1; i <= n; i++) {
            p[i] = Integer.parseInt(st.nextToken());
        }

        dp[0] = 0;
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= i; j++) {
                if(dp[i] < dp[i - j] + p[j]) {
                    dp[i] = dp[i - j] + p[j];
                }
            }
        }
        System.out.println(dp[n]);
    }
}

 

dp[n] = "n개의 카드를 가장 비싸게 살 때 지불하는 금액"

 

dp[n] = dp[n-1] + p[1], dp[n-2] + p[2] + ... + dp[n-n] + p[n] 중 최댁값

dp[i] = dp[i - j] + p[j] (1 <= j <= i) 으로 반복문을 돌린다.

 

O(n^2)으로 처리 가능 (n^2 = 1,000,000)

www.acmicpc.net/problem/2011

 

2011번: 암호코드

나올 수 있는 해석의 가짓수를 구하시오. 정답이 매우 클 수 있으므로, 1000000으로 나눈 나머지를 출력한다. 암호가 잘못되어 암호를 해석할 수 없는 경우에는 0을 출력한다.

www.acmicpc.net

문제

상근이와 선영이가 다른 사람들이 남매간의 대화를 듣는 것을 방지하기 위해서 대화를 서로 암호화 하기로 했다. 그래서 다음과 같은 대화를 했다.

  • 상근: 그냥 간단히 암호화 하자. A를 1이라고 하고, B는 2로, 그리고 Z는 26으로 하는거야.
  • 선영: 그럼 안돼. 만약, "BEAN"을 암호화하면 25114가 나오는데, 이걸 다시 글자로 바꾸는 방법은 여러 가지가 있어.
  • 상근: 그렇네. 25114를 다시 영어로 바꾸면, "BEAAD", "YAAD", "YAN", "YKD", "BEKD", "BEAN" 총 6가지가 나오는데, BEAN이 맞는 단어라는건 쉽게 알수 있잖아?
  • 선영: 예가 적절하지 않았네 ㅠㅠ 만약 내가 500자리 글자를 암호화 했다고 해봐. 그 때는 나올 수 있는 해석이 정말 많은데, 그걸 언제 다해봐?
  • 상근: 얼마나 많은데?
  • 선영: 구해보자!

어떤 암호가 주어졌을 때, 그 암호의 해석이 몇 가지가 나올 수 있는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 5000자리 이하의 암호가 주어진다. 암호는 숫자로 이루어져 있다.

출력

나올 수 있는 해석의 가짓수를 구하시오. 정답이 매우 클 수 있으므로, 1000000으로 나눈 나머지를 출력한다.

암호가 잘못되어 암호를 해석할 수 없는 경우에는 0을 출력한다.

예제 입력 1

25114

예제 출력 1

6

 

 

 

 

 

풀이 .

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

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String pw = br.readLine();
        int n = pw.length();
        int[] dp = new int[n + 1];
        char[] ch = new char[n + 1];
        for(int i = 1; i <= n; i++) {
            ch[i] = pw.charAt(i-1);
        }

        dp[0] = 1;
        for(int i = 1; i <= n; i++) {
            // [i]가 알파벳 하나인 경우
            int num = ch[i] - '0';
            if(1 <= num && num <= 9) {
                dp[i] = dp[i-1];
                dp[i] %= 1000000;
            }
            if(i == 1) continue;

            // [i-1]+[i]가 알파벳 하나인 경우. 10~26
            num = (ch[i-1] - '0') * 10 + (ch[i] - '0');
            if(10 <= num && num <= 26) {
                dp[i] += dp[i-2];
                dp[i] %= 1000000;
            }
        }
        System.out.println(dp[n]);
    }
}

 

dp[n] = "n번째 숫자까지 검사했을 때 나오는 경우의 수"

 

1. n번째 숫자가 알파벳 하나인 경우 -> n번째 숫자가 0이 아니어야 함 (1~26 이니까)

2. n-1, n번째 숫자가 알파벳 하나인 경우 -> n-1, n번째 숫자를 이어붙인 것이 10~26 안에 들어와야 함

 

각 조건이 충족될 때 각각 dp[n-1], dp[n-2] 을 더해준다.

 

 

 

범위 설정에 주의하자

int x = ch[i] - '0';
if(1 <= x && x <= 9)
와
if('1' <= ch[i] && ch[i] <= '9')
는 같다.
.
.
int x = (ch[i-1] - '0') * 10 + (ch[i] - '0');
if(10 <= x && x <= 26)
와
if('1' <= ch[i-1] && ch[i-1] <= '2'  // 십의자리
        && '0' <= ch[i] && ch[i] <= '6') {  // 일의자리
는 다르다.

 

char를 바로 사용하려다가 위와 같은 실수를 범했다.

 

한자리 숫자를 검사하는 경우에서는 괜찮았지만 두자리 숫자를 검사할 때 문제가 생겼다.

 

저 경우에선 17, 18, 19 를 고려하지 못한다.

 

www.acmicpc.net/problem/2225

 

2225번: 합분해

첫째 줄에 답을 1,000,000,000으로 나눈 나머지를 출력한다.

www.acmicpc.net

문제

0부터 N까지의 정수 K개를 더해서 그 합이 N이 되는 경우의 수를 구하는 프로그램을 작성하시오.

덧셈의 순서가 바뀐 경우는 다른 경우로 센다(1+2와 2+1은 서로 다른 경우). 또한 한 개의 수를 여러 번 쓸 수도 있다.

입력

첫째 줄에 두 정수 N(1 ≤ N ≤ 200), K(1 ≤ K ≤ 200)가 주어진다.

출력

첫째 줄에 답을 1,000,000,000으로 나눈 나머지를 출력한다.

예제 입력 1

20 2

예제 출력 1

21

 

 

 

 

 

 

풀이 .

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

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        int k = Integer.parseInt(st.nextToken());
        int[][] dp = new int[n + 1][k + 1];

        dp[0][0] = 1;
        for(int i = 0; i <= n; i++) {
            for (int j = 1; j <= k; j++) {
                for (int m = 0; m <= i; m++) {
                    dp[i][j] += dp[i - m][j - 1];
                    dp[i][j] %= 1000000000;
                }
            }
        }
        System.out.println(dp[n][k]);
    }
}

 

점화식을 도출하는 과정이 codeung.tistory.com/124 와 비슷한 느낌이다.

결국 이것도 못 풀고 정답코드를 확인했다..

 

dp[n][k] = 숫자 n을 숫자 k개의 조합으로 만들 수 있는 경우의 수 (k개의 숫자들을 더한 결과가 n이 되는 경우의 수)

 

n = ? + ? + ? + ... + m 에서 점화식을 유도할 수 있다.

dp[n][k] = dp[n - m][k - 1] (0 <= m <= n 의 모든 m에 대한 값을 더한 것이 dp[n][k]가 된다.)

 

n은 1~200인데 i 반복은 0부터 시작하는 이유?

[0][1]~[0][k] 를 먼저 구해놔야 다음 반복의 점화식에서 사용할 수 있다.

 

[0][1]~[0][k] 는 어차피 전부 1이니까 (0만 k개 더하는 경우) 좀 더 명확하게 알아보기 위해 초기화용 반복을 따로 돌리고 본 반복은 i = 1 부터 시작하는 것도 방법이다.

 

O(k*n^2) 의 시간으로 정답을 구할 수 있다.

 

 

 

 

 

 

너무.. 어렵다.....

 

 

www.acmicpc.net/problem/9461

 

9461번: 파도반 수열

오른쪽 그림과 같이 삼각형이 나선 모양으로 놓여져 있다. 첫 삼각형은 정삼각형으로 변의 길이는 1이다. 그 다음에는 다음과 같은 과정으로 정삼각형을 계속 추가한다. 나선에서 가장 긴 변의

www.acmicpc.net

문제

오른쪽 그림과 같이 삼각형이 나선 모양으로 놓여져 있다. 첫 삼각형은 정삼각형으로 변의 길이는 1이다. 그 다음에는 다음과 같은 과정으로 정삼각형을 계속 추가한다. 나선에서 가장 긴 변의 길이를 k라 했을 때, 그 변에 길이가 k인 정삼각형을 추가한다.

파도반 수열 P(N)은 나선에 있는 정삼각형의 변의 길이이다. P(1)부터 P(10)까지 첫 10개 숫자는 1, 1, 1, 2, 2, 3, 4, 5, 7, 9이다.

N이 주어졌을 때, P(N)을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, N이 주어진다. (1 ≤ N ≤ 100)

출력

각 테스트 케이스마다 P(N)을 출력한다.

예제 입력 1

2

6

12

예제 출력 1

3

16

 

 

 

 

 

풀이 .

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

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());
        while(T-- > 0) {
            int n = Integer.parseInt(br.readLine());
            long[] dp = new long[101];
            dp[1] = 1;
            dp[2] = 1;
            dp[3] = 1;
            dp[4] = 2;
            dp[5] = 2;
            for(int i = 6; i <= n; i++) {
                dp[i] = dp[i-1] + dp[i-5];
            }
            System.out.println(dp[n]);
        }
    }
}

 

그림을 따라가다보면 dp[n] = dp[n-1] + dp[n-5] 의 규칙을 찾을 수 있다.

 

다 풀어놓고 자료형이 안 맞아서 틀렸습니다를 받아 왜인지 한참을 고민했다.

 

DP문제를 풀 때는 long을 "항상" 고려하자

www.acmicpc.net/problem/2133

 

2133번: 타일 채우기

3×N 크기의 벽을 2×1, 1×2 크기의 타일로 채우는 경우의 수를 구해보자.

www.acmicpc.net

문제

3×N 크기의 벽을 2×1, 1×2 크기의 타일로 채우는 경우의 수를 구해보자.

입력

첫째 줄에 N(1 ≤ N ≤ 30)이 주어진다.

출력

첫째 줄에 경우의 수를 출력한다.

예제 입력 1 복사

2

예제 출력 1 복사

3

힌트

아래 그림은 3×12 벽을 타일로 채운 예시이다.

 

 

 

 

풀이 1. (틀린 코드)

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

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        int[] dp = new int[n+1];
        dp[0] = 1;
        dp[1] = 0;
        for(int i = 2; i <= n; i++) {
            if(i == 2) {
                dp[i] = 3;
                continue;
            }
            if(i % 2 == 1) {
                dp[i] = 0;
                continue;
            }
            dp[i] = dp[i-2] * 3 + dp[i-4] * 2;
        }
        System.out.println(dp[n]);
    }
}

 

일단 n이 홀수인 경우는 절대로 타일을 다 채울 수 없다.

i = 2, 3 일 때는 조건문으로 따로 처리하고 4부터 반복이 제대로 돌게 했다.

i 번째로 올 수 있는 경우가 i-2, i-4 두 가지 경우만 있을 거라고 생각했는데, 이게 잘못된 생각이었다.

거의 다 온 거였는데.. 아쉽다.

 

 

 

풀이 2. (정답 코드)

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

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

 

i 번째에 도달할 수 있는 경우

1. i-2번째에서 3가지 경우 존재

2. i-4 부터 -2씩 반복하며 0이 될 때까지 2가지씩 계속 존재

www.acmicpc.net/problem/1699

 

1699번: 제곱수의 합

어떤 자연수 N은 그보다 작거나 같은 제곱수들의 합으로 나타낼 수 있다. 예를 들어 11=32+12+12(3개 항)이다. 이런 표현방법은 여러 가지가 될 수 있는데, 11의 경우 11=22+22+12+12+12(5개 항)도 가능하다

www.acmicpc.net

문제

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

주어진 자연수 N을 이렇게 제곱수들의 합으로 표현할 때에 그 항의 최소개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 자연수 N이 주어진다. (1 ≤ N ≤ 100,000)

출력

주어진 자연수를 제곱수의 합으로 나타낼 때에 그 제곱수 항의 최소 개수를 출력한다.

예제 입력 1

7

예제 출력 1

4

 

 

 

 

 

풀이 1. (틀린 코드)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        int cnt = 0;
        while(n > 0) {
            int temp = (int)Math.sqrt(n);
            n -= Math.pow(temp, 2);
            cnt += 1;
        }
        System.out.println(cnt);
    }
}

DP 문제인 걸 알면서도 방법을 떠올리지 못해 수학으로 풀었다.

큰 제곱수부터 하나씩 빼가면 될 거라고 생각했는데 반례에 걸렸다.

ex ) 18 = 9^2 + 9^2 -> 2개, (코드에서는 16 + 1 + 1 으로 3개 나옴)

 

 

 

풀이 2. (정답 코드)

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

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());

        int[] dp = new int[n + 1];
        dp[0] = 0;
        for(int i = 1; i <= n; i++) {
            dp[i] = i;
            for(int j = 1; j*j <= i; j++) {
                if(dp[i] > dp[i - j*j] + 1) {
                    dp[i] = dp[i - j*j] + 1;
                }
            }
        }
        System.out.println(dp[n]);
    }
}

 

혼자 힘으로 풀지 못해 정답 코드를 확인했다.

이런식으로 수식을 조금씩 가지고 놀아야 하는 문제는 도저히 감을 못 잡겠다.

 

dp[n] = n을 표현하는 제곱수의 합의 최소 항의개수

?^2 + ?^2 + ?^2 + ... + j^2 = i

j^2 <= i

 

즉, dp[i] = min(dp[i - j^2]) + 1 (위의 수식에서 j^2를 제외한 좌항의 나머지 총합이 i-j^2 이므로 dp[i - j^2]. 거기다 j^2에 해당하는 1 더함)

j의 범위 1~루트i 안에서 dp[i - j^2] 가 최소가 되는 j를 찾는다.

 

www.acmicpc.net/problem/2579

 

2579번: 계단 오르기

계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. <그림 1>과 같이 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점

www.acmicpc.net

문제

계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. <그림 1>과 같이 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점수를 얻게 된다.

예를 들어 <그림 2>와 같이 시작점에서부터 첫 번째, 두 번째, 네 번째, 여섯 번째 계단을 밟아 도착점에 도달하면 총 점수는 10 + 20 + 25 + 20 = 75점이 된다.

계단 오르는 데는 다음과 같은 규칙이 있다.

  1. 계단은 한 번에 한 계단씩 또는 두 계단씩 오를 수 있다. 즉, 한 계단을 밟으면서 이어서 다음 계단이나, 다음 다음 계단으로 오를 수 있다.
  2. 연속된 세 개의 계단을 모두 밟아서는 안 된다. 단, 시작점은 계단에 포함되지 않는다.
  3. 마지막 도착 계단은 반드시 밟아야 한다.

따라서 첫 번째 계단을 밟고 이어 두 번째 계단이나, 세 번째 계단으로 오를 수 있다. 하지만, 첫 번째 계단을 밟고 이어 네 번째 계단으로 올라가거나, 첫 번째, 두 번째, 세 번째 계단을 연속해서 모두 밟을 수는 없다.

각 계단에 쓰여 있는 점수가 주어질 때 이 게임에서 얻을 수 있는 총 점수의 최댓값을 구하는 프로그램을 작성하시오.

입력

입력의 첫째 줄에 계단의 개수가 주어진다.

둘째 줄부터 한 줄에 하나씩 제일 아래에 놓인 계단부터 순서대로 각 계단에 쓰여 있는 점수가 주어진다. 계단의 개수는 300이하의 자연수이고, 계단에 쓰여 있는 점수는 10,000이하의 자연수이다.

출력

첫째 줄에 계단 오르기 게임에서 얻을 수 있는 총 점수의 최댓값을 출력한다.

예제 입력 1

6

10

20

15

25

10

20

예제 출력 1

75

 

 

 

 

 

풀이 .

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

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        int[] arr = new int[n + 1];
        int[][] dp = new int[n + 1][3];
        for(int i = 1; i <= n; i++) {
            arr[i] = Integer.parseInt(br.readLine());
        }

        dp[1][1] = arr[1];
        dp[1][2] = 0;
        for(int i = 2; i <= n; i++) {
            dp[i][1] = Math.max(dp[i-2][1], dp[i-2][2]) + arr[i];
            dp[i][2] = dp[i-1][1] + arr[i];
        }
        int ans = Math.max(dp[n][1], dp[n][2]);
        System.out.println(ans);
    }
}

 

1칸 뛰기, 2칸 뛰기 가능

연속된 3칸 오르기 불가능

 

n번째 계단은 반드시 밟아야 한다. 선택할 수 있는 경우는 두 개.

1. n번째 계단을 1번 연속 밟는 경우

2. n번째 계단을 2번 연속 밟는 경우

(n번째 계단을 반드시 밟아야 하기 때문에 0번 연속으로 밟는 경우는 고려하지 않음)

 

1번 연속일 때,

이전 계단은 밟지 않았다는 소리. 즉, n-2에서 n으로 온 것. 

n-2번째 계단은 1번 연속일 수도, 2번 연속일 수도 있다.

dp[n][1] = Math.max(dp[n-2][1], dp[n-2][2]) + arr[n];

 

2번 연속일 때,

이전 계단을 반드시 밟았어야 함. 즉, n-1에서 n으로 온 것.

n-1번째 계단을 반드시 1번 연속으로 밟았어야 한다.

dp[n][2] = dp[n-1][1] + arr[n];

 

+ Recent posts