贪心算法(一):找零钱(蓝桥杯版)

贪心法:

  贪心选择是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。贪心选择是采用从顶向下、以迭代的方法做出相继选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题。对于一个具体问题,要确定它是否具有贪心选择的性质,我们必须证明每一步所作的贪心选择最终能得到问题的最优解。通常可以首先证明问题的一个整体最优解,是从贪心选择开始的,而且作了贪心选择后,原问题简化为一个规模更小的类似子问题。然后,用数学归纳法证明,通过每一步贪心选择,最终可得到问题的一个整体最优解。(自己的看法:比如说有数列A0-An,在求其中的Ai时(0<=i<=j)只需要根据之前A0-Ai-1数列找到这个Ai的最优解,找到这个局部最优解,进而找到全部整体最优解)

  1、问题描述
    有n个人正在饭堂排队买海北鸡饭。每份海北鸡饭要25元。奇怪的是,每个人手里只有一张钞票(每张钞票的面值为25、50、100元),而且饭堂阿姨一开始没有任何零钱。请问饭堂阿姨能否给所有人找零(假设饭堂阿姨足够聪明)

  2、输入格式
  第一行一个整数n,表示排队的人数。
  接下来n个整数a[1],a[2],…,a[n]。a[i]表示第i位学生手里钞票的价值(i越小,在队伍里越靠前)

  3、输出格式
  输出YES或者NO

  4、样例
  ①样例输入
   4
   25 25 50 50
  样例输出
   YES

  ②样例输入
   2
   25 100
  样例输出
   NO
  ③样例输入
   4
   25 25 50 100
  样例输出
   YES
 数据规模和约定
  n不超过1000000

解决思路:每次输入判断看这个付款金额是否是比25大如果为25则将前加入到钱包数组里面,如果比25,就需要找钱,找钱的时候就需要贪心每次对找钱就找当前可以找出去的最大值,然后再判断金额是否到达25了,如果还可以再进行判断则可以继续调用递归判断,直到不用再需要找钱为止。如果在钱包数组里面找不到钱找给客人,则结束并输出NO,若每个都可以找到,则输出YES。

代码:

#include
#include
using namespace std;
int top=0;
int p[]={25,50,100};//收到的可能金额数
int num[3]={0};//保存当前的钱包每个纸币的张数
int getmax(int n)//在钱包里面找到与客人实付金额相近的纸币即贪心钱包里面最大的币
{
    for(int i=1;i>=0;i--)
    {
        if(n>p[i]&&num[i]!=0)
           {
               return p[i];
           }

    }
    top=1;
    return -1;
}
int getindex(int n)//找到钱包对应金额所在的下表
{
    for(int i=0;i<3;i++)
    {
        if(n==p[i])
        {
            return i;

        }
    }
    return -1;
}
void dp(int n,int kk)//贪心的部分
{
    if(n==25&&kk==0)//当前金额为25且为客人实付金额直接加入到钱包里面
    {               //kk是用来判断为第几次找钱,第0次说明客人实付金额为25
        num[0]++;
        return ;

    }
    else if(n==25&&kk!=0)//kk不为0时说明之前找过钱了,这个25是找过钱之后剩余的
    {                     //并且客人给的钱已经加入钱包了
        return ;

    }
    int key=getmax(n);//找到钱包里面与当前金额大小相近的纸币,
    int index2=getindex(key);//返回上面找到纸币的下标
    if(index2==-1)//这里是判断如果钱包没找,直接返回,说明这个金额找不开
    {            //之前的getmax()函数里面会将top=1;在主函数里面会进行top
                 //判断
          return ;
    }
    if(kk==0)//将客人付款的纸币加入到钱包中
    {  
        int index1=getindex(n);
        num[index1]++;
    }
    num[index2]--;//找过钱之后对应纸币数减少
    dp(n-key,kk+1);
}
int main()
{
   int n;
   cin>>n;
   int temp[n];
   for(int i=0;i<n;i++)
   {
       cin>>temp[i];
   }
   for(int i=0;i<n;i++)
   {
       int kk=0;
       dp(temp[i],kk);
       if(top==1)//为1说明存在找不开的金额直接返回了
       {
           cout<<"NO";
           break;
       }
   }
    if(top==0)
    {
        cout<<"YES";
    }
    return 0;
}

第一次写与贪心算法有关的,还是以前的课没有好好听,哪里有问题欢迎各位大佬指出来呀!

你可能感兴趣的:(贪心算法,c++,递归法)