코딩테스트/다이나믹 프로그래밍
최장 증가 부분 수열(LIS)
수타.
2023. 6. 8. 20:02
https://www.acmicpc.net/problem/18353
18353번: 병사 배치하기
첫째 줄에 N이 주어진다. (1 ≤ N ≤ 2,000) 둘째 줄에 각 병사의 전투력이 공백을 기준으로 구분되어 차례대로 주어진다. 각 병사의 전투력은 10,000,000보다 작거나 같은 자연수이다.
www.acmicpc.net
이번엔 문제를 푸는 두가지 유형을 통해 풀이를 점검해보려 한다.
랜덤으로 배치된 수열에서 가장 길게 증가하는 수열을 구하는 문제이다.
이때 O(n^2)을 가지는 기본 DP를 활용한 방법은 i 번까지 확인하면서 i번전까지 만족하던거중 가장높은거 +1을 하는방법이다.
import sys
input = sys.stdin.readline
n = int(input())
data = list(map(int,input().split()))
d = [1] * n
for i in range(n):
for j in range(i):
if data[i]<data[j]:
d[i] = max(d[i],d[j]+1)
print(n-max(d))
그 후 dp에서 가장 높은것이 최장수열이기 때문에 전체에서 빼주면 빼야하는 수의 개수가 나온다.
하지만 이는 O(n^2)이기 때문에 bisect를 활용한 O(nlogn)이 방법이 있다.
import sys
input = sys.stdin.readline
n = int(input())
arr = list(map(int,input().split()))
arr = arr[::-1]
dp = [1e7]*n
from bisect import bisect_left
for i in arr:
dp[bisect_left(dp,i)] = i
print(dp.count(1e7))
계속해서 bisect를 통해 자리에 배정해 주는데 이때 계속 증가한다면 계속 맨 오른쪽에 추가될 것이고, 아니라면 중간에 있었던 것 대신 갱신되기 때문에, O(nlogn)만으로 최장증가부분수열을 만들 수 있다.