ABOUT ME

Today
Yesterday
Total
  • [BOJ] 1509 팰린드롬 분할
    PS/BOJ 2020. 7. 15. 18:42

    https://www.acmicpc.net/problem/1509

     

    1509번: 팰린드롬 분할

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

    www.acmicpc.net

    알고리즘: DP

     

    시간복잡도: O(N^2)

     

    접근:

    1. 팰린드롬 문자열

    -> 팰린드롬 문자는 부분 문제의 속성을 지녔기 때문에 Dynamic 으로 접근하기가 용이함.

    2. (특정 규칙을 가지고) 분할 및 개수 구하기

    -> 이 부분도 Dynamic 속성을 응용하기 쉽다. 예를 들어, D[i]: 0~i까지 분할(그룹)의 개수 라고 두면

        D[i] = D[i-1] + 1 (규칙을 만족하지 않아 새로운 그룹을 만들 시)

                D[i-1]       (규칙을 만족하여 이전 그룹에 속할 시)

        이런식으로 계산이 가능하기 때문이다.

     

    ex)

    ABACABA에서 가운데(C) 기준으로 팰린드롬 문자열을 찾아보면,

    {A,B, ACA, B,A}, {A, BACAB, A}, {ABACABA} 

    이런식으로 가장 긴 팰린드롬은 작은 팰린드롬들로 구성되어 있다는 것을 알 수 있다.

     

     

    D[i]: i번째 문자까지 팰린드롬 분할의 개수

    이렇게 두고 i번째 문자에서 좌우로 문자열을 확인하면서 팰린드롬인지 확인하고 DP 배열을 채워나갔다.

     

    차례대로 코드의 점화식 부분을 설명하자면,

    1. D[i] = Min(D[i], D[i-1]+1) : i번째 문자가 팰린드롬에 속하지 않을 시, 새로운 그룹 형성

    2. D[i+j] = Min(D[i+j], D[i-j-1]+1) : i를 기준으로 (i-j)~(i+j)가 팰린드롬을 형성 (홀수 길이: ABA)

    3. D[i+j] = Min(D[i+j], D[i-j] + 1) : i를 기준으로  (i-j+1)~(i+j)가 팰린드롬을 형성 (짝수 길이: ABBA)

     

     

    code
    // 1509 팰린드롬 분할
    
    #include<iostream>
    #include<cstring>
    #define MIN(a, b) (((a)>(b))?(b):(a))
    using namespace std;
    
    int D[2501], l, j;
    char s[2501];
    int main()
    {
    	cin >> s;
    	l = strlen(s);
    	
    	D[0] = 1;
    	for (int i = 1; i < l; i++) 
    		D[i] = 0x7fffffff;
    	
    	for (int i = 0; i < l; i++)
    	{
    		D[i] = MIN(D[i], D[i-1] + 1);
    		j = 1;
    		while (i-j >= 0 && i+j < l)		// ABA
    		{
    			if (s[i-j] != s[i+j]) break;
    			D[i+j] = MIN(D[i+j], D[i-j-1]+1);
    			j++;
    		}
    		j = 1;
    		while (i-j+1 >= 0 && i+j < l)   // AA
    		{
    			if (s[i-j+1] != s[i+j]) break;
    			D[i+j] = MIN(D[i+j], D[i-j]+1);
    			j++;
    		}
    	}
    	cout << D[l-1];
    	return 0;
    }

     

     


    메모리를 추가로 사용하여 (N^2)

    팰린드롬인지 여부를 확인하는 DP 배열을 미리 만들어서 써먹을 수도 있다. 

    ex) P[i][j] : i~j가 팰린드롬인지 여부 (1: 팰린드롬, 0: 팰린드롬X)

     

    for (i = 0 ~ N-1)

        D[i] = Min(D[i], D[i-1]+1)

        for (j = 0 ~ i-1)

            if (P[i][j] == 0) continue

                D[i] = Min(D[i], D[j-1]+1)

     

    'PS > BOJ' 카테고리의 다른 글

    [BOJ] 1520 내리막 길  (0) 2020.07.16
    [BOJ] 1516 게임 개발  (0) 2020.07.15
    [BOJ] 1490 자리수로 나누기  (0) 2020.07.15
    [BOJ] 12852 1로 만들기 2  (0) 2020.07.15
    [BOJ] 1463 1로 만들기  (0) 2020.07.15

    댓글

Designed by Tistory.