Baekjoon 9252 LCS 2
- 최초 작성일: 2021년 9월 21일(화)
- 주소: https://www.acmicpc.net/problem/9252
목차
[TOC]
문제 설명
- LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다.
- 예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.
입력
- 첫째 줄과 둘째 줄에 두 문자열이 주어진다. 문자열은 알파벳 대문자로만 이루어져 있으며, 최대 1000글자로 이루어져 있다.
출력
- 첫째 줄에 입력으로 주어진 두 문자열의 LCS의 길이를, 둘째 줄에 LCS를 출력한다.
-
LCS가 여러 가지인 경우에는 아무거나 출력하고, LCS의 길이가 0인 경우에는 둘째 줄을 출력하지 않는다.풀이 방법
풀이 방법
- LCS 1 문제를 풀었다면 손쉽게 풀 수 있는 문제이다. 기억이 나지 않는다면, 게시된 9251 설명 글을 읽어보면 이해하기 쉬울 것이다.
- 추가적으로, LCS를 string으로 출력해주어야 하기 때문에, dp 정수 배열과, lcs 스트링 배열을 선언해주어 동적 계획법으로 최장 공통 부분 수열과 그 수열의 길이를 각각 저장해준다.
- 아래의 설명은 LCS 1 문제에서 설명한 내용을 별도로 가져온 것이다.
- 예제에서 주어진 ACAYKP 와 CAPCAK를 예로 하면, 첫 입력인 ACAYKP에서 A를 먼저 고르고 CAPCAK의 왼쪽에서부터 하나씩 A와 일치하는지 비교하고, 다음은 C를 고르고 CAPCAK의 왼쪽에서부터 하나씩 C와 일치하는지를 비교하는 식으로, 연속해서 일치하는 횟수를 dp라는 배열에 저장하는 것을 반복한다.
- 다시 말해, 주어진 예제의 입력들을 string 타입의 s1, s2로 각각 선언해주고, s1의 길이 만큼, 그리고 s2의 길이 만큼의 2중 for문을 돌면서 s1과 s2가 같아지는 시점에서 현재 dp값에서 +1 한 값을 다음 인덱스의 dp에 저장해주고, s1과 s2가 다를 때에는, 인접하는 이전 인덱스의 값들의 최대값으로 갱신하도록 해준다.
- 그렇게 생성된 dp배열의 마지막 인덱스가 답이 된다.
- 두 문자열을 문자 하나씩 비교해 나가는 도중, 그 문자가 현재의 lcs에서 더해주면 된다.
- 그렇지 않다면, 현재 비교하는 인덱스 기준으로 바로 이전의 두 가지 경우에서 더 길이가 긴 경우를 기억한다.
- 예제에서 주어진 ACAYKP와 CAPCAK를 비교하는 과정 중에서 lcs [3] [3]에는 lcs [2] [3]과 lcs [3] [2] 둘 중 max인 값을 저장된다.
- 그러면, lcs [3] [3]에는 ACAYKP와 CAPCAK에서 각각 4번째 위치한 Y와 C를 비교할 당시까지의 최선의 답이 저장되는 것이다.
#include <iostream>
#include <string>
#include <algorithm>
#define endl '\n'
using namespace std;
// 백준 9252번: LCS 2 (Longest Common Subsequence, 최장 공통 부분 수열)
int dp[1001][1001];
string lcs[1001][1001];
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
string s1, s2;
cin >> s1 >> s2;
for (int i = 0; i < s1.length(); i++) {
for (int j = 0; j < s2.length(); j++) {
if (s1[i] == s2[j]) {
dp[i+1][j+1] = dp[i][j] + 1;
lcs[i+1][j+1] += lcs[i][j] + s1[i];
}
else {
dp[i+1][j+1] = max(dp[i][j+1], dp[i+1][j]);
if (lcs[i][j+1].length() > lcs[i+1][j].length())
lcs[i+1][j+1] = lcs[i][j+1];
else
lcs[i+1][j+1] = lcs[i+1][j];
}
}
}
cout << dp[s1.length()][s2.length()] << endl;
cout << lcs[s1.length()][s2.length()] << endl;
return 0;
}