Stunning Garbanzo
open main menu
Part of series: PS

2494 BOJ

/ 4 min read

문제

접근

다이내믹 프로그래밍과 역추적을 이용해 해결하였다.

dp[i][l]에는, i번째 이전의 나사들을 지금까지 l번 왼쪽으로 돌렸다면 i번째 나사 이후의 나사들을 정해진 값에 맞추기 위한 최소한의 회전 칸수를 저장한다. 왼쪽으로 돌리는 경우에만 이후 나사들에게 영향을 주고, 왼쪽으로 돌 때는 다같이 돌기 때문에 이전에 어떤 나사에서 얼만큼 돌렸든 왼쪽으로 돌린 총합이 같으면, 이후 나사들의 배열은 같다는 점을 이용한 것이다.

dp[i][l]은 i번째 나사를 왼쪽으로 0 ~ 9 번 돌린 경우, 총 10개의 경우에 대하여 조사하면 구할 수 있다. 왼쪽으로 돌린 후, i번째 나사를 정해진 값에 맞추기 위해 오른 쪽으로 조정한다. 왼쪽으로 돌린 횟수와 오른쪽으로 돌린 횟수 그리고 다음 나사부터 계산한 값(dp[i+1][l’])을 가지고 dp[i][l]을 구한다. 구한 dp[i][l]을 역추적해서 어떤 식으로 돌렸는지 구할 수 있다.

코드

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef const ll cll;

cll N = 10000, INF = N * 10 + 1;
ll n, genesis[N + 1] = {}, goal[N] = {}, dp[N][10] = {{}};

ll find(ll idx, ll prv) {
  if (idx == n) {
    return 0;
  } else if (dp[idx][prv] != -1) {
    return dp[idx][prv];
  }

  ll &result = dp[idx][prv] = INF;
  for (ll cur = 0, nnum, right, turn, next; cur < 10; ++cur) {
    nnum = (genesis[idx] + prv + cur) % 10;
    right = (nnum - goal[idx] + 10) % 10;
    next = (prv + cur) % 10;
    turn = cur + right + find(idx + 1, next);
    result = min(result, turn);
  }

  return result;
}

void track(ll idx, ll prv) {
  if (idx == n) {
    return;
  }

  ll result = dp[idx][prv];
  for (ll cur = 0, nnum, right, turn, next; cur < 10; ++cur) {
    nnum = (genesis[idx] + prv + cur) % 10;
    right = (nnum - goal[idx] + 10) % 10;
    next = (prv + cur) % 10;
    turn = cur + right + find(idx + 1, next);

    if (turn == result) {
      if (cur) {
        cout << idx + 1 << " " << cur << "\n";
      }

      if (right) {
        cout << idx + 1 << " " << -right << "\n";
      }

      return track(idx + 1, next);
    }
  }
}

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

  cin >> n;
  cin.ignore();
  for (ll i = 0; i < n; ++i) {
    char c;
    cin >> c;
    genesis[i] = c - '0';
  }
  cin.ignore();
  for (ll i = 0; i < n; ++i) {
    char c;
    cin >> c;
    goal[i] = c - '0';
  }
  memset(dp, -1, sizeof(dp));

  cout << find(0, 0) << "\n";
  track(0, 0);

  return 0;
}