YouhaverecentlyacquiredanewjobattheBankforAcquiring Peculiar Currencies. Here people can make payments, and deposit or withdraw money in all kinds of strange currencies. At your first day on the job you help a customer from Nijmegia, a small insignificant country famous for its enormous coins with values equal to powers of 10, that is, 1,10,100,1000, etc. This customer wants to make a rather large payment, and you are not looking forward to the prospect of carrying all those coins to and from the vault. You therefore decide to think things over first. You have an enormous supply of Nijmegian coins in reserve, as does the customer (most citizens from Nijmegia are extremely strong). You now want to minimize the total number of coins that are exchanged, in either direction, to make the exact payment the customer has to make. Forexample,ifthecustomerwantstopay83coinstherearemanywaystomaketheexchange. Here are three possibilities:
Option 1. The customer pays 8 coins of value 10, and 3 coins of value 1. This requires exchanging 8+3=11 coins.
Option 2. The customer pays a coin of value 100, and you return a coin of value 10, and 7 coins of value 1. This requires exchanging 1+1+7=9 coins.
Option 3. The customer pays a coin of value 100, and 3 coins of value 1. You return 2 coins of value 10. This requires exchanging 1+3+2=6 coins.
It turns out the last way of doing it requires the least coins possible.
Input • A single integer 0≤ n < 101000, the amount the customer from Nijmegia has to pay. Output
• Output the minimum number of coins that have to be exchanged to make the required payment.
Sample Input
12345678987654321
Sample Output
42
官方题解
只需设二维dp数组,一维表示当前推到数字的哪一位 二维为0表示在当前这一位时的最低货币值,为1表示当前位+1所需的最低货币值
例如83,dp[1, 0] 表示 80 所需最低货币,dp[1, 1]表示90所需最低货币 可得递推式
dp[i+1][0]=min(dp[i][0]+s[i]-‘0’,dp[i][1]+10-s[i]+‘0’)
dp[i+1][1]=min(dp[i][0]+s[i]-‘0’+1,dp[i][1]+10-s[i]+‘0’-1)
一开始理解不了(就是这么菜,,,),加上括号后努力理解理解
f[i+1][0] = min(f[i][0] + s[i]-‘0’, f[i][1]+10-(s[i]-‘0’));
// 如果 i 不进位, i 处是 i-1 不进位,i 用本位上的数 a ,还是 i -1 进一位, i 处计算用 10 - a , 使得和最小
f[i+1][1] = min(f[i][0] + s[i]-‘0’+1, f[i][1]+10-(s[i]-‘0’+1));
// 如果 i 进一位(此时 i 位上数字+1, b = a+1), i 处是 i-1 不进位,i 用本位上的数 b ,还是 i -1 进一位, i 处计算用 10 - b , 使得和最小
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
using namespace std;
const int N = 1006;
string s;
int f[N][2];
int main()
{
int n, i, j;
cin >> s;
n = s.length();
f[0][1] = 1;
for(i = 0; i < n; ++i)
{
f[i+1][0] = min(f[i][0] + s[i]-'0', f[i][1]+10-(s[i]-'0'));
f[i+1][1] = min(f[i][0] + s[i]-'0'+1, f[i][1]+10-(s[i]-'0'+1));
}
printf("%d\n", f[n][0]);
return 0;
}
然后又改了改,换了个可能好理解一些的表达方式,长这样
f[i][0] = min(f[i-1][0] + s[i]-‘0’, f[i-1][1]+10-(s[i]-‘0’));
// 如果 i +1 不向 i 借位 ( i 位上仍然是原数字 a ), 那么 i 处是用本位上的数 a ,还是用 10 - a ,向 i-1 位借 1 (i-1 原数+1) , 能使得和最小
f[i][1] = min(f[i-1][0] + s[i]-‘0’+1, f[i-1][1]+10-(s[i]-‘0’+1));
// 如果 i+1 向 i 借一位(此时 i 位上数字+1,设 b = a+1),那么 i 处是用本位上的数 b ,还是用 10 - b ,向 i-1 位借 1 (i-1 原数+1) , 能使得和最小
尽力了orz
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
using namespace std;
const int N = 1006;
string s;
int f[N][2];
int main()
{
int n, i, j;
cin >> s;
n = s.length();
f[0][0] = min(s[0]-'0', 1+10-(s[0]-'0'));
f[0][1] = min(s[0]-'0'+1, 1+10-(s[0]-'0'+1));
for(i = 1; i < n; ++i)
{
f[i][0] = min(f[i-1][0] + s[i]-'0', f[i-1][1]+10-(s[i]-'0'));
f[i][1] = min(f[i-1][0] + s[i]-'0'+1, f[i-1][1]+10-(s[i]-'0'+1));
}
printf("%d\n", f[n-1][0]);
return 0;
}