Stunning Garbanzo
open main menu
Part of series: PS

2306 BOJ

/ 3 min read

문제

접근

다이내믹 프로그래밍으로 해결하였다.

괄호 문제와 비슷한 풀이방법으로 해결하면 된다. 탐색해야 할 구간이 주어졌을 때, 해당 구간을 둘로 나눠서 각각의 구간 값의 합을 구한다. 만약 구간의 양끝이 ‘a-t’, ‘g-c’쌍을 이루고 있을 경우, 각각의 원소들을 제하고 나머지 구간의 값에 2를 더한 값을 이전에 두 개 구간으로 나눠 구한 값과 비교하여 큰 값을 탐색 하는 구간의 값으로 한다. 구간의 길이가 작은 것부터 차례로 bottom-up 방식으로 구하면 최적의 시간 복잡도로 답을 구할 수 있다.

처음에는 발상을 간단히 하지 못해 많은 시행 착오를 하였다. ‘a-t’, ‘g-c’ 쌍을 지우고 구간을 탐색하는 과정을 잘못 생각하여 오류를 많이 일으켰다. 또한 top-down 방식으로 설계하여 실행시간이 길었다. 점화식을 단순화하며 bottom-up 방식으로 바꾸고 string 대신 char배열을 썼더니 시간을 많이 아낄 수 있었다.

코드

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef const ll cll;
typedef queue<ll> qll;
typedef queue<pll> qpll;
typedef priority_queue<ll> pqll;
typedef priority_queue<pll> pqpll;
typedef vector<ll> vll;
typedef vector<pll> vpll;
typedef vector<vll> vvll;
typedef vector<vpll> vvpll;
#define FOR1(a, A) for (ll a = 0; a < A; ++a)
#define FOR2(a, b, A, B)                                                       \
  for (ll a = 0; a < A; ++a)                                                   \
    for (ll b = 0; b < B; ++b)

cll N = 500;
ll n, dp[N][N] = {{}};
char dna[N+1] = {};

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

  cin >> dna;
  n = strlen(dna);
  for (ll idx = 0; idx < n; ++idx) {
    dp[idx][idx] = 0;
  }

  for (ll len = 2; len <= n; ++len) {
    for (ll st = 0; st + len - 1 < n; ++st) {
      ll en = st + len - 1;
      for (ll mid = st; mid < en; ++mid) {
        dp[st][en] = max(dp[st][en], dp[st][mid] + dp[mid + 1][en]);
      }

      if (dna[st] == 'a' && dna[en] == 't') {
        dp[st][en] = max(dp[st][en], dp[st + 1][en - 1] + 2);
      }
      if (dna[st] == 'g' && dna[en] == 'c') {
        dp[st][en] = max(dp[st][en], dp[st + 1][en - 1] + 2);
      }
    }
  }

  cout << dp[0][n - 1] << "\n";

  return 0;
}