11054번: 가장 긴 바이토닉 부분 수열
첫째 줄에 수열 A의 크기 N이 주어지고, 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ N ≤ 1,000, 1 ≤ Ai ≤ 1,000)
www.acmicpc.net
문제
수열 $S$가 어떤 수 $S_k$를 기준으로 $S_1$ < $S_2$ < ... $S_{k-1}$ < $S_k$ > $S_{k+1}$ > ... $S_{N-1}$ > $S_N$을 만족한다면, 그 수열을 바이토닉 수열이라고 한다.
예를 들어, {10, 20, 30, 25, 20}과 {10, 20, 30, 40}, {50, 40, 25, 10} 은 바이토닉 수열이지만, {1, 2, 3, 2, 1, 2, 3, 2, 1}과 {10, 20, 30, 40, 20, 30} 은 바이토닉 수열이 아니다.
수열 A가 주어졌을 때, 그 수열의 부분 수열 중 바이토닉 수열이면서 가장 긴 수열의 길이를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 수열 A의 크기 N이 주어지고, 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ N ≤ 1,000, 1 ≤ Ai ≤ 1,000)
출력
첫째 줄에 수열 A의 부분 수열 중에서 가장 긴 바이토닉 수열의 길이를 출력한다.
코드
# 다이나믹 프로그래밍
# 가장 긴 증가하는 부분 수열 알고리즘 이용
n = int(input())
sequence = list(map(int, input().split()))
up_dp = [1] * n # 증가하는 수열의 길이를 저장할 리스트
down_dp = [1] * n # 감소하는 수열의 길이를 저장할 리스트
# 증가하는 부분 수열
for i in range(1, n):
for j in range(i):
if sequence[j] < sequence[i]:
up_dp[i] = max(up_dp[i], up_dp[j] + 1)
# 감소하는 부분 수열
for i in range(n - 1, -1, -1):
for j in range(n - 1, i, -1):
if sequence[j] < sequence[i]:
down_dp[i] = max(down_dp[i], down_dp[j] + 1)
answer = 0
for i in range(n):
answer = max(answer, up_dp[i] + down_dp[i])
print(answer - 1)
다이나믹 프로그래밍의 일종인 가장 긴 증가하는 부분 수열 알고리즘을 이용하여 풀이하였다.
1. 증가하는 수열과 감소하는 수열의 길이를 담을 배열 up_dp, down_dp를 모든 원소를 1로 초기화하여 생성한다.
2. 앞에서부터 증가하는 부분 수열들의 길이를 구한다. 이 때 가장 긴 증가하는 부분 수열 알고리즘을 사용한다. 인덱스 i를 1씩 증가시키며 매번 자신보다 작은 인덱스(j)를 모두 탐색하여 자신보다 작은 수 중 가장 큰 dp값(up_dp[j]) + 1과 up_dp[i]를 비교하여 가장 긴 증가하는 수열의 길이를 구하여 up_dp[i]에 저장하고 다음 인덱스(i + 1)로 넘어간다.
3. 감소하는 부분 수열은 뒤에서부터 보면 증가하는 부분 수열이라고도 볼 수 있으므로 거꾸로 오며 1번과 같은 방법으로 부분 수열들의 길이를 저장한다.
4. 이렇게 구한 up_dp와 down_dp의 같은 인덱스의 값의 합이 가장 큰 지점을 구하면 문제의 답을 구할 수 있다.
'문제풀이 > DP' 카테고리의 다른 글
[Python/파이썬] 백준 7579번 앱 (0) | 2022.09.29 |
---|---|
[Python/파이썬] 백준 11066번 파일 합치기 (1) | 2022.09.24 |
[Python/파이썬] 백준 2342번 Dance Dance Revolution (0) | 2022.09.09 |
[Python/파이썬] 백준 17404번 RGB거리 2 (0) | 2022.08.29 |
[Python/파이썬] 백준 10942번 팰린드롬? (0) | 2022.08.23 |