알고리즘/문제 풀이

백준 16500번: 문자열 판별

Themion 2022. 1. 13. 11:19

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

 

16500번: 문자열 판별

첫째 줄에 길이가 100이하인 문자열 S가 주어진다. 둘째 줄에는 A에 포함된 문자열의 개수 N(1 ≤ N ≤ 100)이 주어진다. 셋째 줄부터 N개의 줄에는 A에 포함된 단어가 한 줄에 하나씩 주어진다. A에

www.acmicpc.net

S를 이룰 각 문자열 A_i와 그 길이 A_i_size에 대해, S에서 k부터 시작하는 A_i를 찾고 S[0:k]를 주어진 문자열을 이용해 만들 수 있다면, S[0:k+A_i_size] 역시 만들 수 있다. 이 과정을 k가 0일 때부터 S의 길이까지 반복한다면 S를 주어진 A의 집합만으로 만들 수 있는지 확인할 수 있다.

#include <iostream>
#include <string>

using namespace std;

#define MAX_LEN 100

int main() {
    // 입출력 속도 향상
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    // dp[l]: S.substr(0, l)을 A의 집합만으로 완성시킬 수 있다면 true
    //        이 때 S.substr(0, 0)은 어떤 경우에서도 만들 수 있다고 가정
    bool dp[MAX_LEN + 1] = { true, };
    // N: A의 원소 개수, len: S의 길이 (S.size()의 호출 최소화)
    // idx: dp의 이전 값을 확인할 때 사용할 인덱스
    int N, len, idx;
    // S: A의 부분집합으로 완성시킬 문자열
    // A: S를 완성시키기 위해 주어진 문자열의 집합
    string S, A[MAX_LEN];

    // 주어진 조건을 입력받은 뒤
    cin >> S >> N;
    for (int i = 0; i < N; i++) cin >> A[i];
    // S의 크기를 변수에 별도로 저장
    len = S.size();

    // dp를 활용해 S를 만들 수 있는지 검토
    for (int l = 1; l <= len; l++) for (int i = 0; i < N; i++) {
        // A[i]보다 작은 S의 부분 문자열은 검토하지 않는다
        if (l < A[i].size()) continue;

        // 부분 문자열에서 A[i]를 제거한 만큼의 길이
        idx = l - A[i].size();
        // 부분 문자열의 마지막에 A[i]가 존재하고,
        // 또 마지막의 A[i]를 제거한 부분 문자열을 만들 수 있다면
        // 길이가 l 부분 문자열을 만들 수 있다고 간주
        if (dp[idx] && S.substr(idx, A[i].size()) == A[i]) dp[l] = true;
    }

    // 길이가 len인 부분 문자열, 즉 전체 문자열을 만들 수 있는지 여부를 출력
    cout << (int)dp[len] << '\n';

    return 0;
}