p1658 购物

Posted -guz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了p1658 购物相关的知识,希望对你有一定的参考价值。

题目描述

你就要去购物了,现在你手上有N种不同面值的硬币,每种硬币有无限多个。为了方便购物,你希望带尽量少的硬币,但要能组合出1到X之间的任意值。

分析:

看到题解做法没有说出原理,所以尝试解释一下.

首先,没有1元面值的硬币肯定无解,因为无法组成1元面值,况且如果我们有1元面值的硬币,那我们就能凑出其他面值(话说带多少硬币去买东西?

然后,我们选择从面值为1元开始凑出所有面值的纸币

(这句话和代码有出入,但是原理相同。)

我们每次选择小于等于当前总面值+1的最大面值的硬币。

//记录当前总面值为s

//因为我们此时可以凑出的面值为1~s的钱,我们想要去凑出面值为s+1的情况,所以说我们需要寻找一张面值为s+1的,如果没有,我们的选择将会是最大面值的,再用它(这个面值大的),去和其他面值的拼凑出更大面值.

概括来讲

以这个大面值为底,和之前的小面值,是可以凑出更大的面值的钱的.

//可能有点混乱.

以样例为例↓

1 2 5 10
now为当前面值,ans为选取的个数。
    now=0,ans=0//此时没有选取  
  需要寻找面值<=now+1的硬币.
    now=1,ans=1//此时选取面值为1的
  需要寻找面值<=2的硬币.
    now=3,ans=2//此时选取了面值为2的
  需要寻找面值<=4的硬币
    now=5,ans=3//又选取了面值为2的
  需要寻找面值<=6的硬币
    now=10,ans=4//选取了面值为5的
  需要寻找面值<=11的硬币
    now=20,ans=5//选取了面值为10的
这样我们选取的为1·2·2·5·10,是可以凑出1~20的所有情况的。

总之思想就是每次选择的硬币,是可以和前面已经出现过的面值,继续组成更大面值的,每次选择最大面值(满足条件的)的,我们就可以实现我们的贪心。

每一次都要在找到比当前该凑数钱小的最大面值数,这样就可以在钱币数量相同的情况下可拼凑价值最大。------此话出处

--------------------代码---------------------

#include<bits/stdc++.h>
#define IL inline
#define RI register int
IL void read(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
    while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int x,N,now,ans;
int s[12];
int main()
{
    read(x),read(N);
    for(RI i=1;i<=N;i++)
        read(s[i]);
    std::sort(s+1,s+N+1);
    if(s[1]!=1)
    {
        puts("-1");
        exit(0);
    }
    while(now<x)
    {
        RI i;
        for(i=N;i;i--)
            if(s[i]<=now+1)break;
        ans++;
        now+=s[i];
        //printf("used:%d
",s[i]);
    }
    printf("%d",ans);
}

以上是关于p1658 购物的主要内容,如果未能解决你的问题,请参考以下文章

Vue实现购物小球抛物线的方法实例

如何从 recyclerview 片段传递到另一个 recyclerview 片段

片段必须在创建之前调用寄存器 registerForActivityResult()

Magento:将静态块添加到结帐购物车

将对象列表从片段传递到 recyclerView 适配器

js代码实现购物车效果