Algorithm 문제/μ•Œκ³ λ¦¬μ¦˜ λ¬Έμ œν•΄κ²°μ „λž΅

[c++] Longest Increasing Sequence (문제 ID : LIS, λ‚œμ΄λ„ : ν•˜) :: μ•Œκ³ λ¦¬μ¦˜ 문제 ν•΄κ²° μ „λž΅ 1ꢌ

희은w 2020. 4. 8. 16:35

https://www.algospot.com/judge/problem/read/LIS

문제

μ–΄λ–€ μ •μˆ˜ μˆ˜μ—΄μ—μ„œ 0개 μ΄μƒμ˜ 숫자λ₯Ό μ§€μš°λ©΄ 이 μˆ˜μ—΄μ˜ λΆ€λΆ„ μˆ˜μ—΄ (subsequence) λ₯Ό 얻을 수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄ 10 7 4 9 의 λΆ€λΆ„ μˆ˜μ—΄μ—λŠ” 7 4 9, 10 4, 10 9 등이 μžˆλ‹€. 단, 10 4 7 은 μ›λž˜ μˆ˜μ—΄μ˜ μˆœμ„œμ™€ λ‹€λ₯΄λ―€λ‘œ 10 7 4 9 의 λΆ€λΆ„ μˆ˜μ—΄μ΄ μ•„λ‹ˆλ‹€.

μ–΄λ–€ λΆ€λΆ„ μˆ˜μ—΄μ΄ μˆœμ¦κ°€ν•  λ•Œ 이 λΆ€λΆ„ μˆ˜μ—΄μ„ 증가 λΆ€λΆ„ μˆ˜μ—΄ (increasing subsequence) 라고 ν•œλ‹€. 주어진 μˆ˜μ—΄μ˜ 증가 λΆ€λΆ„ μˆ˜μ—΄ 쀑 κ°€μž₯ κΈ΄ κ²ƒμ˜ 길이λ₯Ό κ³„μ‚°ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜λΌ.

μ–΄λ–€ μˆ˜μ—΄μ˜ 각 μˆ˜κ°€ μ΄μ „μ˜ μˆ˜λ³΄λ‹€ 클 λ•Œ, 이 μˆ˜μ—΄μ„ μˆœμ¦κ°€ ν•œλ‹€κ³  ν•œλ‹€.

μž…λ ₯

μž…λ ₯의 첫 μ€„μ—λŠ” ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ˜ 수 C (<= 50) κ°€ 주어진닀. 각 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ˜ 첫 μ€„μ—λŠ” μˆ˜μ—΄μ— ν¬ν•¨λœ μ›μ†Œμ˜ 수 N (<= 500) 이 주어진닀. κ·Έ λ‹€μŒ 쀄에 μˆ˜μ—΄μ΄ N개의 μ •μˆ˜κ°€ 주어진닀. 각 μ •μˆ˜λŠ” 1 이상 100,000 μ΄ν•˜μ˜ μžμ—°μˆ˜μ΄λ‹€.

좜λ ₯

각 ν…ŒμŠ€νŠΈμΌ€μ΄μŠ€λ§ˆλ‹€ ν•œ 쀄씩, 주어진 μˆ˜μ—΄μ˜ κ°€μž₯ κΈ΄ 증가 λΆ€λΆ„ μˆ˜μ—΄μ˜ 길이λ₯Ό 좜λ ₯ν•œλ‹€.

예제 μž…λ ₯

3
4
1 2 3 4
8
5 4 3 2 1 6 7 8 
8
5 6 7 8 1 2 3 4

예제 좜λ ₯

4
4
4

μƒκ°μ˜ 흐름

  1. μ›λž˜ μˆ˜μ—΄μ—μ„œ 1개 μ—†μ• κΈ°, 2개 μ—†μ• κΈ°, ... , n-1개 μ—†μ• κΈ°κΉŒμ§€ κ°€λ©΄μ„œ 없앨 index의 쑰합을 λͺ¨λ‘ 계산해보기

    μ‘°ν•© λ§Œλ“€κΈ°κ°€ λ„ˆλ¬΄ μ‹«μŒ => λ„ˆλ¬΄ λ³΅μž‘ν•¨..

  2. μ¦κ°€ν•˜λŠ” μ΅œλŒ€κ΅¬κ°„μ°ΎκΈ°

    μ¦κ°€ν•˜λŠ” λΆ€λΆ„μˆ˜μ—΄ 쀑 μ›λž˜ μˆ˜μ—΄μ—μ„œ μ—°μ†μ μœΌλ‘œ ν• λ‹Ήλ˜μ–΄μžˆλŠ” 것듀을 μ‘°μ‚¬ν•œλ‹€.

    κ°€μž₯ 큰 연속 λΆ€λΆ„μˆ˜μ—΄μ„ νƒν•΄μ„œ μ•ž λ’€λ‘œ 더 μž‘κ³  큰 μˆ˜κ°€ μžˆλŠ”μ§€ κ³„μ‚°ν•œλ‹€.

    λ°˜λ‘€ ) 연속적이지 μ•Šμ•„λ„ κ°€μž₯ κΈ΄ μ¦κ°€λΆ€λΆ„μˆ˜μ—΄μ΄ λ‚˜μ˜¬ 수 있음

    => test case 4번째

  3. 각 index μ΄ν›„μ—μ„œ λ‚˜μ˜¬ 수 μžˆλŠ” μ΅œλŒ€ μ¦κ°€μˆ˜μ—΄μ˜ 길이λ₯Ό μ €μž₯해두기

    이후에 λ‚˜μ˜¬ index에 관계없이 각 index λ§ˆλ‹€ μ΅œμ„ μ„ κ²°μ •ν•  수 μžˆλŠ” μ΅œμ λΆ€λΆ„κ΅¬μ‘°μ΄λ―€λ‘œ μž¬κ·€ν•¨μˆ˜λ‘œ '완전탐색 + λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ°' κ΅¬ν˜„ν•  수 μžˆλ‹€.

μ£Όμ˜ν•  점

  1. λ°°μ—΄ λ“± 객체의 size ν•¨μˆ˜λ₯Ό for의 μ‘°κ±΄μ—μ„œ μ“°λ©΄ λ‚΄λΆ€μ—μ„œ λ³€ν•  수 μžˆμœΌλ―€λ‘œ 이λ₯Ό μ΄μš©ν•  λͺ©μ μ΄ μ•„λ‹ˆλ©΄ forλ¬Έ λ“€μ–΄κ°€κΈ° 전에 λ‹€λ₯Έ λ³€μˆ˜λ‘œ 미리 받아두기

    int tmp = arr.size();
    for(int i=0; i<tmp; i++) // for(int i=0; i<arr.size(); i++) ν•˜μ§€λ§κΈ°

μ½”λ“œ

#include <iostream>

using namespace std;
int N;
int arr[500];
int memorize[500];

int LIS(int index) {
    if (memorize[index] != -1)
        return memorize[index];
    else if (index == N - 1)
        return 1;
    int max = 1;
    for (int i = index + 1; i < N; i++) {
        if (arr[index] >= arr[i])
            continue;
        int tmp = LIS(i);
        if (max < 1 + tmp)
            max = 1 + tmp;
    }
    memorize[index] = max;
    return max;
}

int main() {
    int C;
    cin >> C;
    while (C--) {
        cin >> N;
        fill(memorize, memorize + sizeof(memorize) / sizeof(int), -1);
        for (int i = 0; i < N; i++) {
            cin >> arr[i];
        }
        int max = 0;
        for (int i = 0; i < N; i++) {
            int tmp = LIS(i);
            if (tmp > max)
                max = tmp;
        }
        cout << max << endl;
    }
}

test case (λŒ“κΈ€ μ°Έκ³ , 직접 λ§Œλ“  것듀)

6
4
1 2 3 4 
8
5 4 3 2 1 6 7 8 
8
5 6 7 8 1 2 3 4
8
1 5 2 6 3 0 4 7
3
1 1 1
7
9 1 3 7 5 6 20
4
4
4
5
1
5

λ§ˆμ§€λ§‰ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€κ°€ μ•ˆλ˜λŠ” 경우

  1. maxκ°€ λ‚˜μ˜€λŠ” 경우λ₯Ό ν•œ 번만 κ³ λ €ν•œ 경우

    max κΈΈμ΄λŠ” μ—¬λŸ¬ 번 λ‚˜μ˜¬ 수 μžˆμœΌλ―€λ‘œ 각 κ²½μš°μ— λŒ€ν•΄ λ‹€ κ³ λ €ν•΄μ£Όμ–΄μ•Όν•œλ‹€.

    ex_) 9 1 3 7 5 6 20 의 경우 μ—°μ†λœ μˆ˜λ“€ 쀑 (1,3,7), (5,6,20) 두 개의 max μ¦κ°€μˆ˜μ—΄μ΄ λ‚˜μ˜¨λ‹€.

  2. ν•œ index에 λŒ€ν•΄μ„œλ§Œ μ‘°μ‚¬ν–ˆμ„ 경우

    μ™„μ „ νƒμƒ‰μœΌλ‘œ κ΅¬ν˜„ν–ˆμ„ 경우 처음 indexμ—μ„œ 남은 n-1개λ₯Ό μž¬κ·€ν•¨μˆ˜λ‘œ νƒμƒ‰ν•˜λŠ”λ°, 이 λ•Œ indexλ₯Ό ν•˜λ‚˜μ”© μ¦κ°€μ‹œν‚€λ©΄μ„œ νƒμƒ‰ν•΄μ•Όν•œλ‹€.

    ex_) 0번째 μ›μ†Œμ— λŒ€ν•΄ 1~n-1번째 μ›μ†Œλ₯Ό 탐색 => 1번째 μ›μ†Œμ— λŒ€ν•΄ 2~n-1번째 μ›μ†Œλ₯Ό 탐색

    μ—¬κΈ°μ„œ 0번째 μ›μ†Œμ— λŒ€ν•΄μ„œλ§Œ κ΅¬ν˜„ν•˜κ³  λͺ¨λ“  indexλ₯Ό κ³ λ €ν•˜λ„λ‘ 반볡문 처리λ₯Ό μ•ˆν•΄μ€¬μ„ 경우 ν•΄λ‹Ή ν…ŒμŠ€νŠΈμΌ€μ΄μŠ€κ°€ μ œλŒ€λ‘œ μž‘λ™λ˜μ§€ μ•ŠλŠ”λ‹€.

  3. 더 λΉ λ₯Έ 해법

μ•žμ—μ„œλΆ€ν„° 배열에 λ„£μœΌλ©΄μ„œ μ¦κ°€μˆ˜μ—΄μ΄ μ•„λ‹ˆκ²Œ 될 λ•Œ, ν•΄λ‹Ή μˆ˜κ°€ μœ„μΉ˜ν•΄μ•Όν•  곳에 μ‚½μž…ν•΄μ€Œ

ν•΄λ‹Ή μˆ˜κ°€ μœ„μΉ˜ν•΄μ•Όν•  곳은 μ΄μ§„νƒμƒ‰μœΌλ‘œ μ°ΎκΈ°

μ‹œκ°„λ³΅μž‘λ„κ°€ O(nlgn)이닀.

n : μ²˜μŒλΆ€ν„° λκΉŒμ§€ μ‹œν–‰

1 : μ¦κ°€μˆ˜μ—΄μ΄ μ΄μ–΄μ§€λŠ” 지 확인

lgn : μ΄μ§„νƒμƒ‰μœΌλ‘œ μ‚½μž…ν•  μœ„μΉ˜ μ°ΎκΈ°

μ½”λ“œ : https://jaimemin.tistory.com/317

λ°˜μ‘ν˜•