[백준] 최대 증가 부분 수열(LIS) 문제

2021. 7. 14. 22:41알고리즘 관련/DP

가장 긴 증가하는 부분 수열 (실 2) : https://www.acmicpc.net/problem/11053
가장 긴 증가하는 부분 수열 4 (골 4) :https://www.acmicpc.net/problem/14002

DP에 관하여 워낙 유명한 문제.

여기서는 LIS를 실제로 출력하는 코드를 위주로 살펴본다.


1. (일반적인) 최대 증가 부분 수열의 길이 반환

 

#include <iostream>
#include <stdio.h>
#include <memory.h>

using namespace std;

int N, A[1001], cache[1001];

int lis(int start)
{
  int &ret = cache[start + 1];

  if (ret != -1)
    return ret;

  ret = 1;

  for (int i = start + 1; N > i; i++)
    if (start == -1 || A[start] < A[i])
      ret = max(ret, lis(i) + 1);

  return ret;
}

int main(void)
{
  int k;

  cin >> N;

  for (int i = 0; N > i; i++)
  {
    scanf("%d", &k);
    A[i] = k;
  }

  memset(cache, -1, sizeof(cache));

  int maxLen = 0;

  maxLen = lis(-1);

  cout << maxLen - 1<< '\n';

  return 0;
}

 


 

2. LIS 실제 출력 문제

실제 답 계산 레시피(https://sanghoonly.tistory.com/44)를 참고.

#include <iostream>
#include <stdio.h>
#include <memory.h>
#include <vector>

using namespace std;

int N, A[1001], cache[1001];
int choices[1001];  // 어느 숫자를 다음 숫자로 선택해야, LIS의 길이를 최대화 할 수 있을지를 기록하는 배열.
vector<int> result; // lis 실제 결과를 담는 벡터.

int lis(int start)
{
  int &ret = cache[start + 1];

  if (ret != -1)
    return ret;

  ret = 1;

  int bestNext = -1; // LIS 길이를 최대화할 선택의 idx.

  for (int i = start + 1; N > i; i++)
    if (A[start] < A[i])
    {
      int cand = lis(i) + 1;
      if (cand > ret)
      {
        bestNext = i;
        ret = cand;
      }
    }

  choices[start + 1] = bestNext; //최적 선택을 choices에다 저장.

  return ret;
}

// choice값을 이용하여, LIS를 재구성하는 재귀 함수.
void reconstruct(int start, vector<int> &seq)
{
  if (start != -1)
    seq.push_back(A[start]); // 선택 값을 벡터에다 저장.

  // lis 함수에서 choices[start + 1]에 최적 선택의 인덱스를 담았으므로, 이를 복원.
  int next = choices[start + 1]; 

  if (next != -1)
    reconstruct(next, seq);
}

int main(void)
{
  int k;

  cin >> N;

  for (int i = 0; N > i; i++)
  {
    scanf("%d", &k);
    A[i] = k;
  }

  memset(cache, -1, sizeof(cache));
  memset(choices, -1, sizeof(choices));

  int maxLen = 0;

  maxLen = lis(-1) - 1;

  cout << maxLen << '\n';

  reconstruct(-1, result);

  for (auto e : result)
  {
    cout << e << ' ';
  }
  return 0;
}

 

'알고리즘 관련 > DP' 카테고리의 다른 글

[백준] RGB 거리  (0) 2021.07.15
[백준] 1, 2, 3 더하기 3  (0) 2021.07.14
[백준] 제곱수의 합  (0) 2021.07.14
[백준] 합분해  (0) 2021.07.14
[백준] 1로 만들기  (0) 2021.07.06