티스토리 뷰

www.acmicpc.net/problem/1509

 

1509번: 팰린드롬 분할

세준이는 어떤 문자열을 팰린드롬으로 분할하려고 한다. 예를 들어, ABACABA를 팰린드롬으로 분할하면, {A, B, A, C, A, B, A}, {A, BACAB, A}, {ABA, C, ABA}, {ABACABA}등이 있다. 분할의 개수의 최솟값을 출력하

www.acmicpc.net

주어진 문자열을 팰린드롬으로 나누는 경우 중 분할된 개수의 최솟값을 구하는 문제입니다.

ABACABA의 경우 문제에 나와있듯이 {A,B,A,C,A,B,A}, {A,BACAB,A}, {ABA,C,ABA}, {ABACABA} 와 같이 나타낼 수 있고 이 때는 분할의 최소 개수가 1입니다.

 

풀이 : dp를 이용해 풀었습니다.

 

1. 주어진 문자열에 대해 i번째 문자부터 j번째 문자가 팰린드롬인지 확인합니다. 팰린드롬이면 dp[ i ][ j ] = true, 아니면 false 입니다.

 

i > j인 경우는 안 해도 되므로 2500+2499+...+1 = O(n^2) 임을 알 수 있습니다. 최대 길이가 2500인 string에 대한 연산이므로 대략적으로 팰린드롬이 되는지 체크 (is_pelindrom)를 1250 번 돈다고 계산했을 때 시간초과에 약간의 우려가 있습니다. (제한시간 2초)

 

2. dp[i] : 첫번째 문자부터 i번째 문자까지 팰린드롬 분할의 최소 개수

 

계산의 편의를 위해 string의 맨 앞에 '.'을 붙혔습니다. (첫번째 알파벳 = index 1)

또한 dp[0]=0으로 잡고, dp[1]=1 입니다.

이제 dp[i] = min(dp[i], dp[ j-1 ]+1) 임을 알 수 있습니다. j는 i부터 1까지 돌고, pelin[ j ][ i ]가 true이면 j 부터 i 번째 문자열은 팰린드롬이므로 dp[ j - 1 ] + 1을 해주면 됩니다.

( j가 첫번째 문자에 해당될 수 있으므로 dp[-1]을 정의하기 위해 string의 맨 앞에 '.'을 붙혔습니다.)

 

여기서 최대 2500*2500 번 연산을 한다고 잡으면 (실제로는 n(n+1)/2) 600만번 연산이므로 제한시간 2초에 통과합니다. i 부터 j까지가 팰린드롬인지 확인하는 과정에서 겹치는 부분이 있어서 시간을 줄이고 싶다면 여기를 처리하면 됩니다.

 

코드는 다음과 같습니다.

#include<iostream>
#include<algorithm>
#include<string>

using namespace std;

string s;
int len; // s의 길이, '.'포함
bool pelin[2501][2501]; // pelin[x][y] : index가 x부터 y까지가 펠린드롬이면 true, 아니면 false
int dp[2501]; // dp[i] : i번째까지 펠린드롬 최소 개수
// dp[i] = min(dp[i], dp[j-1]+1) 
// j : i부터 1까지 돌면서 펠린드롬이면 직전값+1로 업데이트

void init()
{
	cin >> s;
	s.insert(0, "."); 
	// 맨 앞에 '.' 추가 : 맨 처음문자까지 돌았을 때 펠린드롬이면 dp[0]=0으로 생각 
	len = s.size();
	for (int i = 0; i < len; i++) {
		for (int j = 0; j < len; j++) {
			pelin[i][j] = false;
		}
		dp[i] = 987654321;
	}
}

bool is_pelindrom(int start, int last)
{
	int mid = (start + last) / 2; // 가운데값
	int i = 0;
	bool check = true;
	while ((start + i) <= mid) {
		if (s[start + i] != s[last - i]) {
			check = false;
			break;
		}

		i++;
	}
	return check;
}

void make_pelindrom()
{
	for (int i = 1; i < len; i++) {
		for (int j = i; j < len; j++) {
			if (is_pelindrom(i, j))
				pelin[i][j] = true;
		}
	}
}

void calculate_dp()
{
	dp[0] = 0;
	dp[1] = 1;

	for (int i = 2; i < len; i++) {
		for (int j = i; j > 0; j--) {
			if(pelin[j][i])
				dp[i] = min(dp[i], dp[j - 1] + 1);
		}
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);

	init();
	make_pelindrom();
	calculate_dp();
	cout << dp[len - 1];
}

 

'알고리즘 > 백준' 카테고리의 다른 글

백준 / 1517 버블 소트 C++  (0) 2021.04.09
백준 / 5373 큐빙 C++  (0) 2021.04.08
백준 / 1800 인터넷 설치 C++  (0) 2021.04.03
백준 / 2174 로봇 시뮬레이션 C++  (0) 2021.04.03
백준 / 1041 주사위 python3  (0) 2021.04.01
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
TAG
more
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함