C++每日一练:硬币的面值(终于填了这天坑)


前言

遇到这题好几回了!可我一直没能通过…
一直以为是水平问题,害我严重怀疑小学数学没过关。今天又遇到了它,我又是各种折腾啊~ 没办法的时候我都去偷师了,CSDN网上有二篇写这题的!不过也没比我的小学数学好到哪去,也不知能不能过了100%,反正我怎么改都是90%,我看着思路都差不多,没图没证据!
然后我又去找GPT请教,都请教到不理我了!回答问题次数到了,也没问出个所以然,GPT在这题上幼儿园都没毕业!
想到我还有文心一言!我找小文去问问!
小文给了我如下代码:

cpp
复制代码
#include <iostream>  
#include <string>  
#include <sstream>  
#include <vector>  
#include <algorithm>  
  
using namespace std;  
  
int find_if(int n, std::vector<int> &vec){  
    int result=0;  
    // TODO:  
    sort(vec.begin(),vec.end());  
    int sum = 0, i = 0;  
    while(sum < m){  
        sum += (i < vec.size() ? vec[i] : vec[i-1]);  
        i++;  
    }  
    return result;  
}  
  
int solution(int n, int m, std::vector<int>& vec){  
    int result=0;  
    // TODO:  
    sort(vec.begin(),vec.end());  
    int sum = 0, i = 0;  
    while(sum < m){  
        sum += find_if(sum+1, vec);  
        cout << "now sum = " << sum << endl;  
        result++, i++;  
    }  
    return result;  
} 

这个才让人无语…我就问小文:
在这里插入图片描述
然后它就成复读机了…
复读了两回后,我忍不住了!bty:GPT也被问复读了,别因此段对话以为GPT比小文好,至少在这个问题上都一样!
在这里插入图片描述

最后下定决心复习小学数学~ 请教了隔壁家8岁小孩,终于搞定了!
有图为证:
在这里插入图片描述


1. 题目

题目描述:
小A有n枚硬币,现在要买一样不超过m元的商品,他不想被找零,同时又不想带太多的硬币,且硬币可以重复,现在已知这n枚硬币的价值,请问最少需要多少硬币就能组合成所有可能的价格?

输入描述:
第一行两个数:n、m。 下一行,共n个数字,表示硬币的面值。

输出描述:
一行一个数,表示最少需要多少硬币。如果无解请输出“No answer!!!”

示例:
输入
5 31
1 2 8 4 16

输出
5

2. 分析

首先,这题要仔细读题,最先我就踩了没仔细读题的坑,我给看成要用n个硬币凑出m的值,最无语的是样例也这么误导人。多次0%再重读题后搞明白了是要求,用n个面值的无限数量的硬币,凑出m及以下的任意值!因为预估的是最高值为m,很可能价格要低,又不要找零(虽然他自己带一堆零钱),但他就这么任性!这样我们就可以分析出(以示例来看):
首先要取的是1面值的一个,因为货物价格可能是1至m!
然后取2面值一个,这样可以组合出1,2,3。 以此类推。
那假设没有4面值怎么办?很显然就再取一个2,这样能组合出1,2,3,4,5。一个还不够!再来一个2面值,就有1到7,然后再取8面值一个。
以此推导…这有了主要思路,就可以写代码了,写完再改嘛~

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>

using namespace std;

int solution(int n, int m, std::vector<int>& vec){  
    int result=0;  
    // TODO:  
    sort(vec.begin(), vec.end());
    int sum = 0, i = 0, L = vec.size(), tmp;
    if (*max_element(vec.begin(),vec.end())==1) sum = m, result = m;  //注1
    while(sum<m && L>1){
        if (find(vec.begin(), vec.end(), 1) == vec.end()) {     //注2
            //cout << "No answer!!!";
            result = 0;
            break;
        }
        if(sum+1 < vec[i+1]){
            tmp = vec[i];
            sum += tmp;
            result++;
        }else if(sum+1 == vec[i+1]){
            tmp = vec[i+1];
            sum += tmp;
            result++;
            i++;
        }else{
            i++;
        }
        if (i == L-1){    //注3
            int sum_sub = (m-sum);
            result += (sum_sub/vec[L-1]) + (bool(sum_sub%vec[L-1]));
            break;
        }
    }
    return result;  
} 

注1:此处原没写得这么复杂,原是写在循环内的判断,如果vec[0]不为1,就输出No answer!!!,后来因为老过不了,就给改成这样了,这句是为了防止1 0 0 0 1这样的输入面值,因为排序后,0在最前面,就可能得不到正确结果,实际多次测试来看,没有这样的测试数据,所以这句可以没有。
注2:此处同上原因改的,注1 是防止只有1的情况,这是防止排序后0在最前的问题。
注3:这里其实不要也能得出正确结果,但是会超时,这样写是在当取到最大面值后,没必要再一个个去取了,直接取最大的,用的除法一次算出。
其实估计很多人都做出类似的答案了,但就算这样也只能过90%!
这就对了,真的!剩下的是题目的坑,去看main函数吧~


总结

最后隔壁小孩告诉我:抄答案是不对的!所以我就把答案写出来了~
把main的输出std::cout改一改就好了!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无证的攻城狮

如本文对您有用,大爷给打个赏!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值