Benelux Algorithm Programming Contest 2019 E. Efficient Exchange(动态规划dp)

这篇博客介绍了如何解决一个关于高效硬币交换的问题,其中涉及尼梅贾国家的独特货币系统,硬币值为10的幂。问题在于找出支付特定金额时最小的硬币交换次数。通过动态规划方法,可以找到最优解,例如支付83个硬币时,使用一枚100的硬币和3枚1的硬币交换次数最少,仅需6次。文章提供了解决方案的递推公式和代码实现。
摘要由CSDN通过智能技术生成

Efficient Exchange

https://nanti.jisuanke.com/t/44331
E. Efficient Exchange

Google翻译中文题意

您最近在银行获得了一份新奇的货币工作。人们可以在这里付款,并以各种奇怪的货币存入或提取钱。在工作的第一天,您会帮助来自奈梅贾的客户,奈梅贾是一个微不足道的小国,以巨大的硬币而闻名,其价值等于10的幂,即1、10、100、1000等。该客户希望相当大的一笔付款,您不希望携带所有这些硬币往返金库。
因此,您决定先思考。您和客户一样都有大量的尼吉米亚硬币储备(大多数尼吉米亚公民都非常强大)。现在,您要尽量减少在任一方向上交换的硬币总数,以准确支付客户必须支付的费用。

例如,如果客户要支付83个硬币,则有很多方法可以进行兑换。这是三种可能性:

  • 方法1: 客户支付8个价值10的硬币和3个价值1的硬币。这需要交换8 + 3 = 11个硬币。
  • 方法2:客户支付了一个价值100的硬币,您返回了价值10的硬币和7个价值1的硬币。这需要交换1 +1 + 7 = 9个硬币。
  • 方法3:客户支付一枚价值100的硬币和3枚价值1的硬币。您返回2枚价值10的硬币。这需要交换1 + 3 + 2 = 6枚硬币。

事实证明,这样做的最后一种方法需要最少的硬币。

输入
0 ≤ n < 1 0 1000 0\le n < 10^{1000} 0n<101000,客户必须支付的金额的一个整数。

输出
输出为进行所需付款而必须兑换的最小硬币数量。


样例输入1
83
样例输出1
6
样例输入2
13
样例输出2
4
样例输入3
12345678987654321
样例输出3
42


题解:
考虑 1254 x 1254x 1254x , 令 a = 12540 , b = 12550 , a = 12540, b = 12550, a=12540,b=12550,
可得 1254 x = 12540 + x 1254x = 12540+x 1254x=12540+x 或者 12550 − 10 + x , 12550 - 10 + x, 1255010+x,
所以 1254 x 1254x 1254x 最少兑换货币 = M i n ( a + x , b + 10 − x ) = Min(a+x, b+10-x) =Min(a+x,b+10x)
dp递归图解
只需设二维dp数组,一维表示当前推到数字的哪一位
二维为0表示在当前这一位时的最低货币值,为1表示当前位+1所需的最低货币值
例如83, d p [ 1 , 0 ] dp[1, 0] dp[1,0] 表示 80 所需最低货币, d p [ 1 , 1 ] dp[1, 1] dp[1,1]表示90所需最低货币
可得递推式
d p [ i ] [ 0 ] = m i n ( d p [ i − 1 ] [ 0 ] + s [ i ] − ′ 0 ′ , d p [ i − 1 ] [ 1 ] + 10 − s [ i ] + ′ 0 ′ ) dp[i][0]=min(dp[i-1][0]+s[i]-'0',dp[i-1][1]+10-s[i]+'0') dp[i][0]=min(dp[i1][0]+s[i]0,dp[i1][1]+10s[i]+0)
d p [ i ] [ 1 ] = m i n ( d p [ i − 1 ] [ 0 ] + s [ i ] − ′ 0 ′ + 1 , d p [ i − 1 ] [ 1 ] + 10 − s [ i ] + ′ 0 ′ − 1 ) dp[i][1]=min(dp[i-1][0]+s[i]-'0'+1,dp[i-1][1]+10-s[i]+'0'-1) dp[i][1]=min(dp[i1][0]+s[i]0+1,dp[i1][1]+10s[i]+01)

递归的套路,先写成递归,再自下而上递推,转化成动态规划。

Code:

#include <bits/stdc++.h>
using namespace std;
int dp[10005][2];
int main()
{
	char s[10005];
	scanf("%s", s + 1);
	int len = strlen(s + 1);
	dp[0][0] = 0;
	dp[0][1] = 1;
	for (int i = 1; i <= len; i++)
	{
		dp[i][0] = min(dp[i - 1][0] + s[i] - '0', dp[i - 1][1] + 10 - s[i] + '0');
		dp[i][1] = min(dp[i - 1][0] + s[i] - '0' + 1, dp[i - 1][1] + 10 - s[i] + '0' - 1);
	}
	printf("%d\n", dp[len][0]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值