-
[백준] #9252 LCS2(Longest Common Subsequence) - (DP)Algorithm/알고리즘 백준 풀이 2020. 3. 2. 17:01
문제
https://www.acmicpc.net/problem/9252
9252번: LCS 2
LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.
www.acmicpc.net
목표
두개의 문자가 주어졌을때 두 문자의 부분수열중 최장길이의 부분수열을 구하는 문제
풀이
dp를 사용하여 각 구간마다 최장부분수열의 길이를 저장시켜놓는다.
사진에서 동그라미 친 부분은 두 문자열의 부분문자가 같은 구간 => dp값이 1증가해야한다.
점화식
dp[i][j] = if (s1[i] == s2[j]) dp[i-1][j-1] + 1;
= else max( dp[i-1][j], dp[i][j-1] );
코드
1. 재귀로구현
#include <iostream> #include <cstring> #include <stack> #define MAX 1001 using namespace std; //dp[i][j]: i행 j열위치에서 확인한 LCS의 최대값 int dp[MAX][MAX]; string str1; string str2; stack<char> s; //지나간 dp배열값은 모두 0이상의 값으로 초기화됨 => 트래킹 가능 int func(int i, int j) { //문자열을 비교할수있는 범위를 넘어가면 0으로 초기화 if (i <= 0 || j <= 0) return dp[i][j] = 0; int &ref = dp[i][j]; if (ref != -1) return ref; //문자열의 문자가 서로 같은경우 대각선의 dp값 + 1 if (str1[i-1] == str2[j-1]) { ref = func(i-1, j-1) + 1; } //문자열의 문자가 서로 다른경우 dp의 왼쪽, 위쪽중 최대값을 가짐 else { ref = max(func(i, j-1), func(i-1, j)); } return ref; } int main() { cin >> str1 >> str2; memset(dp, -1, sizeof(dp)); cout << func(str1.length(), str2.length()) << '\n'; // cout << '\n' << '\n'; // for (int i=0; i<=str1.length(); i++) { // for (int j=0; j<=str2.length(); j++) { // cout << dp[i][j] << " "; // } // cout << '\n'; // } //트래킹작업 //1. 왼쪽비교, 2. 위쪽비교 => 값이 현재값과 같다면 LCS문자열이 아니다. //3. 대각선비교 => 값이 현재값-1 이라면 LCS문자열이다. int i = str1.length(); int j = str2.length(); while (i>0 && j>0) { int tmp = dp[i][j]; //왼쪽값과 같다면 왼쪽이동 if (tmp == dp[i][j-1]) { --j; continue; } //위쪽값과 같다면 위쪽이동 if (tmp == dp[i-1][j]) { --i; continue; } //대각선값+1값과 같다면 대각선이동 if (tmp-1 == dp[i-1][j-1]) { --i; --j; s.push(str1[i]); continue; } return 0; } //추적한 값 출력 while (!s.empty()) { cout << s.top(); s.pop(); } // cout << '\n' << '\n'; // for (int i=0; i<=str1.length(); i++) { // for (int j=0; j<=str2.length(); j++) { // cout << dp[i][j] << " "; // } // cout << '\n'; // } }
2. 반복으로구현
#include <iostream> #include <vector> #include <stack> #define MAX 1001 using namespace std; string s1; string s2; int dp[MAX][MAX]; stack<char> s; void func() { int len1 = s1.length(); int len2 = s2.length(); for (int i=1; i<=len1; ++i) { for (int j=1; j<=len2; ++j) { if (s1[i-1] == s2[j-1]) dp[i][j] = dp[i-1][j-1] + 1; else dp[i][j] = max(dp[i-1][j], dp[i][j-1]); } } cout << dp[len1][len2] << '\n'; while (dp[len1][len2] != 0) { if (dp[len1][len2] == dp[len1][len2-1]) len2--; else if (dp[len1][len2] == dp[len1-1][len2]) len1--; else { s.push(s1[len1-1]); len1--; len2--; } } while (!s.empty()) { cout << s.top(); s.pop(); } } int main() { cin >> s2 >> s1; func(); }
'Algorithm > 알고리즘 백준 풀이' 카테고리의 다른 글
[백준] #11049 행렬 곱셈 순서 - (DP) (0) 2020.03.02 [백준] #19115 가장 큰 정사각형 - (DP) (0) 2020.03.02 [백준] #11659 구간합 구하기4 - (DP) (0) 2020.03.02 [백준] #2579 계단 오르기 - (DP) (0) 2020.03.02 [백준] #1932 정수삼각형 - (DP) (0) 2020.03.02