人人车笔试算法题,类似找零问题,求解

william624 2016-07-16 02:42:22
假设有100、50、20、10、5、1六种面额的纸币。根据交易金额给出最少使用的纸币数(六种面额随意使用,无限制)。比如交易金额为19元,则顾客给出20元,商家找回1元,一共用了两张纸币。再比如交易金额31元,顾客可以给出50和1元,然后商家找回20元,一共三张。当然也可以10+20+1.给出算法,对任意交易面额给出最少使用纸币数量。
...全文
286 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
灌水号 2016-07-19
  • 打赏
  • 举报
回复
引用 11 楼 wanren13 的回复:
[quote=引用 9 楼 u014444402 的回复:] [quote=引用 8 楼 u014444402 的回复:]

#include <stdio.h>

int m[] = {100,  50, 20, 10, 5,  1};



int FindChange( int n, int s)
{
		int a = 0, b = 0;
		int i;
		int c = 0;
		if ( n <= 3 )
        {
            return n;
        }

        c = n / m[s];
        a = FindChange( n % m[s], s+1 );
        b = 1 +  FindChange( m[s] - n % m[s], s+1 );
        if ( a >= b  )
        {

            return b + c;
        }

        return a + c;
}

int main()
{
    int i=80;
    for ( i=1; i<100; i++ )
    {
        printf("%d:%d\n", i, FindChange(i, 0));
    }

	return 0;
}

可以求出数量.
[/quote] 答案看似是正确的,但是必须要证明贪心得到的的确是最优解,而且递归的重复计算太多。[/quote] 你确定你真的看懂了? 递归重复计算太多,你看看才递归了几次?最多2^6次方.
wanren13 2016-07-18
  • 打赏
  • 举报
回复
引用 9 楼 u014444402 的回复:
[quote=引用 8 楼 u014444402 的回复:]

#include <stdio.h>

int m[] = {100,  50, 20, 10, 5,  1};



int FindChange( int n, int s)
{
		int a = 0, b = 0;
		int i;
		int c = 0;
		if ( n <= 3 )
        {
            return n;
        }

        c = n / m[s];
        a = FindChange( n % m[s], s+1 );
        b = 1 +  FindChange( m[s] - n % m[s], s+1 );
        if ( a >= b  )
        {

            return b + c;
        }

        return a + c;
}

int main()
{
    int i=80;
    for ( i=1; i<100; i++ )
    {
        printf("%d:%d\n", i, FindChange(i, 0));
    }

	return 0;
}

可以求出数量.
[/quote] 答案看似是正确的,但是必须要证明贪心得到的的确是最优解,而且递归的重复计算太多。
xskxzr 2016-07-18
  • 打赏
  • 举报
回复
100以内打表,否则贪心。
wanren13 2016-07-18
  • 打赏
  • 举报
回复
我详细说明一下吧: 比方说我们要求80的最优解 先用动规先求得凑到80的最优解为3 (50 + 20+10) 对于凑钱最优解为3的情况,我们最多只能找一张钱。因为如果找两张的话没有意义(付一张,找两张,一共三张,最优解3已经求得)。对于找一张的情况,我们对于大于80的值的解的要求为1。 有可能存在最优解的值为 80 + 1 = 81 80 + 5 = 85 80 + 10 = 90 80 + 20 = 100 80 + 50 = 130 80 + 100 = 180 6种情况。 用动规在80的基础上计算到180。我们发现100的最优解为1(100本身),1(本身) + 1(找的20) = 2 < 3, 所以最优解为2。 以上是凑钱的最优解为3的情况。(50 + 20 + 10) 如果我们的凑钱的最优解不是3,而是n,那么我们就需要对多个区间去求最优解。对于n,最多能找回的钱的数量不能多于n - 2。对于找回n - 2数量的零钱,对应的解为n - 2 + m(直接凑所需的钱的数量的最优解), 对于n - 3的区间对应的是最优解为 n - 3 + m(直接凑所需的钱的数量的最优解),以此类推。。。 分别求出各个区间的局部最优,最后比较获得全局最优。
wanren13 2016-07-18
  • 打赏
  • 举报
回复
用动规正着求一遍(最少多少张可以凑成所需的数目),再用动规反着求一遍(找零的话最少多少张),取最小值
灌水号 2016-07-18
  • 打赏
  • 举报
回复
引用 8 楼 u014444402 的回复:

#include <stdio.h>

int m[] = {100, 50, 20, 10, 5, 1};



int FindChange( int n, int s)
{
int a = 0, b = 0;
int i;
int c = 0;
if ( n <= 3 )
{
return n;
}

c = n / m[s];
a = FindChange( n % m[s], s+1 );
b = 1 + FindChange( m[s] - n % m[s], s+1 );
if ( a >= b )
{

return b + c;
}

return a + c;
}

int main()
{
int i=80;
for ( i=1; i<100; i++ )
{
printf("%d:%d\n", i, FindChange(i, 0));
}

return 0;
}


可以求出数量.


灌水号 2016-07-18
  • 打赏
  • 举报
回复

#include <stdio.h>

int m[] = {100,  50, 20, 10, 5,  1};



int FindChange( int n, int s)
{
		int a = 0, b = 0;
		int i;
		int c = 0;
		if ( n <= 3 )
        {
            return n;
        }

        c = n / m[s];
        a = FindChange( n % m[s], s+1 );
        b = 1 +  FindChange( m[s] - n % m[s], s+1 );
        if ( a >= b  )
        {

            return b + c;
        }

        return a + c;
}
可以求出数量.
bravery36 2016-07-18
  • 打赏
  • 举报
回复
找零算法最复杂的地方是钱箱容量不是无限的,所以不是像lz想的那么简单。比如说找零60元,十元及以下的钱箱空了,但是20元的钱箱还有钱,你如果用了大面额的50元就会找零失败。
Ethan722 2016-07-17
  • 打赏
  • 举报
回复
先除面值最大的取余,在用余数除以面值第二大的取余,再用余数再除以面值第三大的取余数,以此类推。再把所有的商加起来。不晓得对不对,我是这样想的
lm_whales 2016-07-17
  • 打赏
  • 举报
回复
我觉得,可以先用除法求出不足解法。 然后求出对应的剩余解法的替代方案。 求出所有替代方案中最省纸币的方法
lm_whales 2016-07-17
  • 打赏
  • 举报
回复
2)两张100,-->80 至此可以不必选了,一定比第一方案多
lm_whales 2016-07-17
  • 打赏
  • 举报
回复
给出一个金额, 除了刚好合适除外, 有两种方案待选 1)不足近似方案,就是取整 2)剩余近似方案,就是取整加一 反复应用比较,选取最终纸币用量最少的方案 举例 120 --> 1)一张 100,--> 还需要 20 -->一张20 共两张,顾客出120 共1张100,一张20 2)两张200,-->80 至此可以不必选了,一定比第一方案多

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧