蓝桥杯-计蒜客之买书

必须写一个博客来出出心中这口恶气,因为每次遇到递归的问题都会卡很长时间,这次也不例外(生气的表情:哼)

题干:

  蒜头君去书店买书,他有 m 元钱,书店里面有 n 本书,每本书的价格为 pi 元。蒜头君很爱学习,想把身上钱都用来买书,并且刚好买 k 本书。请帮蒜头君计算他是否能刚好用 m 元买 k 本书。

输入格式

  第一行输入 3 个整数 m(1m100000000),n(1n30),k(1kmin(8,n))

  接下来一行输入 n 个整数,表示每本书的价格 pi(1pi100000000)。

输出格式

  如果蒜头君能刚好用 m 元买 k 本书,输入一行"Yes", 否则输出"No"

样例输入1

10 4 4
1 2 3 4

样例输出1

Yes

样例输入2

10 4 3
1 2 3 4

样例输出2

No

问题分析:
  咱们先想一下递归的原理:递归就是重复地做一件事,直到遇到某个条件成立时再停止递归。下面再来看这道题,这道题实质上也在重复地做一件事,即判断是否要买当前的书,如果买了那么接下来应该怎么做;
如果没买那么接下来又应该怎么做。
  我写的递归函数是这个形式的:void dfs(int mon,int pos,int cnt) ,其中mon代表当前的钱数,pos代表当前正在考虑的是哪一本书(注意:是正在考虑,而不是已经买了或者没买),cnt代表当前已经买了几本书(当然不包括当前正在考虑的这本书)

注意:写法一是对的,写法二是错误的。原因是(1)式代表的是买书,所以应该减去当前这本书的价格,但是(2)式代表的是不买书,所以他不应该减去这本书的价格 (这一部分看不懂也没关系,与其它部分没有联系)
   还有就是递归的结束条件要把握好,有的题的结束条件很好找,比如求阶乘问题;但有的题的条件不是不好找而是找不全,比如这道题。 所以递归的难点在于找到“重复的过程“和“结束条件”。
void dfs(int mon,int pos,int cnt)
{
    if(mon==0 && cnt==k){
        judge=true;
        return ;
    }
    if(mon<=0 || cnt>k){
        return ;
    }
    if(pos>=n){
        return ;
    }
写法一:
    dfs(mon-price[pos],pos+1,cnt+1); 
    dfs(mon,pos+1,cnt); 
写法二:
    mon -= price[pos];
    dfs(mon,pos+1,cnt+1); (1)
    dfs(mon,pos+1,cnt);  (2)
}

 

 

代码如下:

#include<iostream>
using namespace std;
typedef long long LL;

int n,k;
LL price[35]={0};
bool judge=false;

void dfs(int mon,int pos,int cnt)
{
    if(mon==0 && cnt==k){
        judge=true;
        return ;
    }
    if(mon<=0 || cnt>k){
        return ;
    }
    if(pos>=n){
        return ;
    }
    dfs(mon-price[pos],pos+1,cnt+1);
    dfs(mon,pos+1,cnt);
}

int main()
{
    LL m;
    while(cin>>m>>n>>k){
        judge=false;
        for(int i=0;i<n;i++){
            cin>>price[i];
        }
        dfs(m,0,0);
        if(judge){
            cout<<"Yes"<<endl;
        }
        else{
            cout<<"No"<<endl;
        }
    }
}

 



posted @ 2018-03-25 16:49  ACPIE  阅读(504)  评论(0)    收藏  举报