Problem : https://www.acmicpc.net/problem/1965
1965번: 상자넣기
정육면체 모양의 상자가 일렬로 늘어서 있다. 상자마다 크기가 주어져 있는데, 앞에 있는 상자의 크기가 뒤에 있는 상자의 크기보다 작으면, 앞에 있는 상자를 뒤에 있는 상자 안에 넣을 수가
www.acmicpc.net
Difficulty : Silver 5
Status : Solved
Time : 00:30:32
더보기
정육면체 모양의 상자가 일렬로 늘어서 있다. 상자마다 크기가 주어져 있는데, 앞에 있는 상자의 크기가 뒤에 있는 상자의 크기보다 작으면, 앞에 있는 상자를 뒤에 있는 상자 안에 넣을 수가 있다. 예를 들어 앞에서부터 순서대로 크기가 (1, 5, 2, 3, 7)인 5개의 상자가 있다면, 크기 1인 상자를 크기 5인 상자에 넣고, 다시 이 상자를 크기 7인 상자 안에 넣을 수 있다. 하지만 이렇게 상자를 넣을 수 있는 방법은 여러 가지가 있을 수 있다. 앞의 예에서 차례대로 크기가 1, 2, 3, 7인 상자를 선택하면 총 4개의 상자가 한 개의 상자에 들어가게 된다. 상자의 크기가 주어질 때, 한 번에 넣을 수 있는 최대의 상자 개수를 출력하는 프로그램을 작성하시오.
더보기
입력
파일의 첫 번째 줄은 상자의 개수 n (1 ≤ n ≤ 1000)을 나타낸다. 두 번째 줄에는 각 상자의 크기가 순서대로 주어진다. 상자의 크기는 1,000을 넘지 않는 자연수이다.
출력
첫째 줄에 한 줄에 넣을 수 있는 최대의 상자 개수를 출력한다.
입력 예시
8
1 6 2 5 7 3 5 6
출력 예시
5
최장 증가 부분 수열(LIS) 문제. N <= 1000이므로 O(N^2)으로 풀어도 되지만, 지식을 점검하고자 O(NlogN) 방법으로 풀었다.
핵심은 최장 증가 부분 수열을 저장하면서, 어떤 새로운 수를 넣을 위치를 lower bound로 탐색하는 것이다. lower bound란 어떤 수 k가 주어졌을 때 k보다 크거나 같은 값이 처음 나타나는 위치 를 의미한다.
[1, 2, 6, 7]이라는 리스트에 3이라는 수를 집어넣고자 하면, 이 리스트의 lower bound에 위치하는 6 자리에 3을 추가하면 된다.
이런 식으로 한 번 리스트를 순회한 후, 최장 증가 부분 수열 리스트의 길이를 반환하면 된다.
풀이 코드
N = int(input())
num_list = list(map(int, input().split()))
def lower_bound(target, lis_list) :
start, end = 0, len(lis_list)
while start < end :
mid = (start + end) // 2
if lis_list[mid] < target :
start = mid + 1
else :
end = mid
lis_list[end] = target
def full_search() :
lis_list = [num_list[0]]
for num in num_list[1:] :
if lis_list[-1] < num :
lis_list.append(num)
else :
lower_bound(num, lis_list)
print(len(lis_list))
full_search()
풀이완료~