백준 문풀/icpc25w

백준 9252 Lcs 2

조강학 2025. 1. 26. 20:27

문제

LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다.

예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.

입력

첫째 줄과 둘째 줄에 두 문자열이 주어진다. 문자열은 알파벳 대문자로만 이루어져 있으며, 최대 1000글자로 이루어져 있다.

출력

첫째 줄에 입력으로 주어진 두 문자열의 LCS의 길이를 출력한다.


처음에는 vector<vector<string>> answer배열을 만들고

dp 배열을 업데이트 할 때마다 같이 값을 업데이트 해줬는데,, 시간초과가 났다. 순회하면서 string 배열을 계속 확인하는데 시간이 좀 걸리나보다;; 

 

그래서 dp배열의 역추적을 이용해 문자열을 구해보기로 하였다. 

dp 배열을 끝에서부터 확인하면서 a[i]==b[j]라면 정답 문자열에 추가하고 i와 j를 감소시킨다.

같지 않은 경우 dp[i-1][j]>= dp[i][j]라면 i만 감소시키고 , 이것도 아니라면 j를 하나 감소시켰다.

 

dp배열이 대각선으로 이동할 수 있는 경우는 현재 확인하고 있는  i, j 인덱스에서 문자가 같음을 확인한 경우고,

아니라면 왼쪽이나 위쪽으로 이동하는데 여기서 그냥 dp값이 큰 쪽으로 이동하면 된다. 

위나 아래로 이동하는데 dp값은 작아지거나 같은 경우만 있으므로 

해당 코드가 정상적으로 작동할 수 있게 된다.

 

이런 느낌으로 추적한다 

 

#include<iostream>
#include<vector>
#include <string>

using namespace std;

int main() {
	ios::sync_with_stdio(0);

	string a;
	string b;

	cin >> a;
	cin >> b;

	int s = a.size();
	int t = b.size();

	vector<vector<int>>dp(s+1,vector<int>(t+1,0));
	vector<char>answer;

	for (int i = 0; i < s; i++) {
		for (int j = 0; j < t; j++) {
			if (a[i] == b[j]) {
				dp[i+1][j+1] = dp[i][j] + 1;
			}
			else {
				if (dp[i + 1][j] > dp[i][j + 1]) {
					dp[i + 1][j + 1] = dp[i + 1][j];
				}
				else {
					dp[i + 1][j + 1] =  dp[i][j + 1];
				}
			}
		}
	}

	int i = s, j = t;
	while (i > 0 && j > 0) {
		if (a[i - 1] == b[j - 1]) {
			// 현재 문자가 일치하면 LCS에 추가하고 대각선으로 이동
			answer.push_back(a[i - 1]);
			i--;
			j--;
		}
		else if (dp[i - 1][j] >= dp[i][j - 1]) {
			// 위쪽으로 이동
			i--;
		}
		else {
			// 왼쪽으로 이동
			j--;
		}
	}

	cout << dp[s][t]<<"\n";

	for (int i = answer.size() - 1; i>= 0; i--) {
		cout << answer[i];
	}
	return 0;

}

 

어떻게 dp배열로 문자열을 찾아내는지 생각하는데 시간이 좀 걸렸다,, 연습을 좀 더 해야겠다!~

'백준 문풀 > icpc25w' 카테고리의 다른 글

백준 1520 내리막 길  (0) 2025.01.28
백준 9251 Lcs  (0) 2025.01.26
백준 5214 환승  (0) 2025.01.24
백준 11657 타임머신  (0) 2025.01.23
백준 1504 특정한 최단 경로  (0) 2025.01.22