발상 & 점화식
역추적
DP 배열에 이전 인자를 저장하는 방식으로 역추적할 수 있다. 사용한 인자는 이전에 양의 방향으로 돌린 횟수와 자물쇠 인덱스인데, 자물쇠 인덱스는 항상 1씩 증가하므로 별도로 저장할 필요는 없다. 양의 방향과 음의 방향으로 돌렸을 때 비용이 적은 쪽의 인자와 그 때 발생한 비용을 저장하면 역추적할 수 있다.
코드
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
struct node {
int v = -1, c, p = -1;
};
int n; string s, d;
vector<vector<node>> dp;
int r(int c, int sp) {
if (c == n) return 0;
if (dp[c][sp].v != -1) return dp[c][sp].v;
int psp = (d[c] - '0' - (s[c] - '0' + sp) % 10 + 10) % 10;
int nsp = 10 - psp;
int s1 = r(c + 1, (sp + psp) % 10) + psp;
int s2 = (nsp == 10 ? 21e8 : r(c + 1, sp) + nsp);
dp[c][sp].c = s1 < s2 ? psp : -nsp; // 최적일 때 발생한 비용 저장
dp[c][sp].p = s1 < s2 ? (sp + psp) % 10 : sp; // 최적일 때의 인자 저장
return dp[c][sp].v = s1 < s2 ? s1 : s2;
}
void printpath(int c, int sp) { // 0, 0부터 역추적
if (c == n) return;
cout << c + 1 << " " << dp[c][sp].c << "\n";
printpath(c + 1, dp[c][sp].p);
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0);
cin >> n; dp = vector<vector<node>>(n + 1, vector<node>(10));
cin >> s >> d;
cout << r(0, 0) << "\n";
printpath(0, 0);
return 0;
}