본문 바로가기
프로그래밍/Baekjoon & Codeup

[백준] 12015번 가장 긴 증가하는 부분 수열2 문제 풀이(c++)

by Homo_Viator 2024. 3. 28.

문제 링크 - https://www.acmicpc.net/problem/12015

 

12015번: 가장 긴 증가하는 부분 수열 2

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000,000)

www.acmicpc.net

문제 설명

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오.

예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {1020, 10, 30, 20, 50} 이고, 길이는 4이다.

 

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다.

둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000,000)

 

첫째 줄에 수열 A의 가장 긴 증가하는 부분 수열의 길이를 출력한다.

 

아이디어

lower bound를 이용하여 최장 증가 부분 수열의 길이를 구할 수 있습니다. 

이때, lower bound는 특정 값의 시작 위치를 찾는 알고리즘인데요.

찾고자 하는 값 이상의 값이 처음으로 나타나는 위치를 말합니다.

예를 들어 1,3,5,5,7이라는 수열이 있을 때 lower bound(5)는 5이상의 값이 처음으로 나타나는 빨간색 부분을 의미합니다.

1,3,5,5,7

 

 

수열에서 현재 수를 a라고 했을 때 a가 벡터의 마지막 값보다 크면 벡터에 삽입하고

a가 벡터의 마지막 값보다 작으면 lower bound를 해서 나온 index위치의 값을 a로 교체할 것입니다.

최종적으로 만들어진 벡터의 길이가 최장 증가 수열의 길이가 될 것입니다.

 

그러나 lower bound만으로 문제를 풀면 LIS의 값을 직접 구할 수는 없다는 점을 기억하셔야 합니다!

(lower bound는 이분탐색을 기반으로 알고리즘을 구현할 수 있지만 본 소스코드에선 C++ STL을 활용했습니다.)

 

소스코드
#include <bits/stdc++.h>
using namespace std;
int arr[1000001];
vector<int>v;

int main()
{
    int N; scanf("%d %d",&N,&arr[0]);

    v.push_back(arr[0]);
    for(int i=1;i<N;i++)
    {
        scanf("%d",&arr[i]);
        if(v.back()<arr[i])
        {
            v.push_back(arr[i]);
        }
        else
        {
            int index=(lower_bound(v.begin(),v.end(),arr[i])-v.begin());
            v[index] = arr[i];
        }
    }
    printf("%d",v.size());
}

 

이 코드를 응용하여 LIS와 관련된 많은 문제를 풀 수 있을 것입니다.

비슷한 문제

- 1365번 꼬인 전깃줄 (풀이 링크 : https://nomadsjh.tistory.com/67)

- 2352번 반도체 설계

- 1818번 책정리

- 14003번 가장 긴 증가하는 부분 수열(풀이 링크 : https://nomadsjh.tistory.com/68)

등등등...

 

감사합니다!

728x90