[백준] 11055번 가장 큰 증가하는 부분 수열 JAVA (자바) 풀이
문제 11055번 (DP)
: 수열 A가 주어졌을 때, 그 수열의 증가하는 부분 수열 중에서 합이 가장 큰 것을 구해라
예를 들어, 수열 A = {1, 100, 2, 50, 60, 3, 5, 6, 7, 8} 인 경우에 합이 가장 큰 증가하는
부분 수열은 A = {1, 100, 2, 50, 60, 3, 5, 6, 7, 8} 이고, 합은 113
[입력]
: 첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000)
둘째 줄에는 수열 A를 이루고 있는 Ai (1 ≤ Ai ≤ 1,000)
[출력]
: 수열 A의 합이 가장 큰 증가하는 부분 수열의 합을 출력
[설명]
DP 알고리즘
: 이미 계산된 결과는 별도의 메모리 영역에 저장하여 다시 계산하지 않음으로서 수행 시간 단축시키는 방법
DP 구현 방법은 일반적으로 Top-down(하향식)과 Bottom-up(상향식)으로 구성된다
탑다운 (Top-Down) | 보텀업 (Bottom-Up) |
작은 크기로 문제를 나눠서 해결 | 작은 것부터 해결해서 점차 빌드업 |
메모제이션 (memoization) | 타뷸레이션 (tabulation) |
일부만 계산해도 답이 나올 때 | 모두 계산해야 답이 나올 때 |
재귀 | 반복문 |
시간 복잡도 O(n) | 시간 복잡도 O(n) |
1. 브루트포스의 원리 이용하기
- 시작지점 하나를 고정하고 나머지 지점들을 돌려가며 비교한다
- dp[i] = arr[i] 으로 시작지점고정
- 시작지점의 값과 비교했을 때 더 작은 값이라면 수열을 다시 세거나 이전값들과 합쳐서 이어가거나 해야한다
= 현지점에서 시작할 지 더 이전 지점에서 시작할 지 택
예) {1, 100, 2, 50, 60, 3, 5, 6, 7, 8}
- 시작지점 고정
dp[2] = arr[2] = 2 - 시작지점 전의 인덱스들 모두 검사하는데 값이 더 작은 경우
arr[0] ~ arr[1] 중에 값이 2보다 더 작은경우는 arr[0] - 그냥 고정한 시작지점이 더 최대인지 시작지점보다 더 낮은 지점에서 현재지점까지 세는게 더 최대인지 택
Math.max(dp[2], dp[0]+arr[2])
- 최적의 dp중 최대값 출력
[코드]
import java.io.*;
import java.util.*;
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];
int arr[] = new int[N];
int result = 0;
StringTokenizer st = new StringTokenizer(br.readLine());
for(int i=0; i<N; i++){
arr[i] = Integer.parseInt(st.nextToken());
}
for(int i =0;i<N;i++){
dp[i] = arr[i];
for(int j=0; j<i; j++){
if(arr[j]<arr[i]){
dp[i] =Math.max(dp[i], dp[j]+arr[i]);
}
}
result = Math.max(result, dp[i]);
}
System.out.println(result);
}
}
[해설]
: BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
int dp[] = new int[N]; dp 배열 초기화
int arr[] = new int[N]; 수열 담을 배열 초기화
int result = 0; 결과 초기화
: StringTokenizer st = new StringTokenizer(br.readLine());
for(int i=0;i<N;i++){
arr[i] = Integer.parseInt(st.nextToken()); 수열 입력 받기
}
: for(int i=1;i<N;i++){ 1부터 시작
dp[i] = arr[i]; 현 지점만 담기 (시작지점을 현지점으로 하겠다는 의미)
for(int j=0; j<i; j++){
if(arr[j]<arr[i]){ 현지점보다 이전 인덱스 배열 값 중 더 작은 값이 있다면
dp[i] =Math.max(dp[i], dp[j]+arr[i]); 현지점에서 시작 vs 더 작은값에서 시작
}
}
result = Math.max(dp[i], result); 최적의 값만 저장한 dp 배열 중 최대값 뽑기
}
: System.out.println(result); 결과 출력
이제 풀어보러 갈께요 :)
https://www.acmicpc.net/problem/11055
* 독학으로 익히는 코딩이라 틀린 것이 있을 수 있습니다. 오류가 있다면 댓글을 통해 알려주세요. 감사합니다. *