秒懂百科,C++如此简单丨第十三天:贪心算法

目录

Everyday English

引子

1、纸币问题

题目概要

解题思路

示范代码

2、洛谷(P1658 购物 C++)

题目概要

解题思路

示范代码

结尾


 必看信息 

▶本篇文章由爱编程的小芒果原创,首发于CSDN,未经许可,严禁转载。

▶本篇文章被收录于秒懂百科,C++如此简单专栏,欢迎订阅。

☆专栏亮点☆

1.每篇文章质量高,质量分保证在80分以上。

2.文章的内容清晰有条理,图文并茂,附有源代码。

3.每个知识点讲解详细,会有很多补充扩展。

4.若哪个知识点没有懂,可以私信我,我会尽可能地帮助你。

Everyday English

One minute on the stage needs ten years practice off stage.

台上一分钟,台下十年功

引子

什么是贪心?

其实就是遵循某种规则不断贪心地选取当前最优策略地算法设计方法

简单来说,就是用最优策略去解问题

那做题的框架呢?

没有框架!就是找到贪心的思路,照着编就行了。

我个人认为,贪心其实跟数学逻辑息息相关。就是用数学逻辑去找到或思考贪心思路,再用程序写出来。因此贪心的两大主要步骤就是确定贪心思路和编程

话不多说,我们来看几道例题。

1、纸币问题

题目概要

现有纸币1元,5元,10元,20元,50元,100元若干枚,要求分别输入这些面值硬币的个数,以及一个总钱数a元。问:至少用多少个硬币才能凑出a元?

解题思路

根据直觉和生活中的常识,我们可以得到以下解答:

       先尽可能地使用100元的硬币。

       剩下的再尽可能地使用50元的硬币。

       剩下的再尽可能地使用20元的硬币。

       剩下的再尽可能地使用10元的硬币。

       剩下的再尽可能地使用5元的硬币。

       最后使用1元的硬币。

所以这题的贪心思路就是:优先使用大面值的硬币

示范代码

知道了贪心思路,代码也就迎刃而解了,送上代码:
#include<bits/stdc++.h>
using namespace std;
int v[6]={1,5,10,20,50,100};
int main(){
	int c[6],a,ans=0;
	for(int i=0;i<6;i++) cin>>c[i];
	cin>>a;
	for(int i=5;i>=0;i--){ //倒序,优先使用大面值的硬币
	int x=min(c[i],a/v[i]); //使用x张该面值的硬币,min来检查这个面值的张数够不够 
	ans+=x;//加上张数 
	a-=x*v[i];//总钱数减去当前面值最大用去的 
	}
	cout<<ans<<endl;
	return 0;//好习惯 
}
这个问题可以算是贪心算法中的一个 简单的例子,我们遵循着“ 优先使用大面值 的规则,得到的
解答就是最优的

2、洛谷(P1658 购物 C++)

我也有一篇专门讲解这题的博客,内容和你看到的一样。

题目概要

题目描述:

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

输入格式:

第一行两个数 X, N,以下 N 个数,表示每种硬币的面值。

输出格式:

最少需要携带的硬币个数,如果无解输出 -1。

输入输出样例:

输入:20   4                       输出:5

           1     2      5     10

解题思路

这道题是一道经典的贪心问题,你得先弄清楚贪心策略

首先,我们必须得有一枚1元面值的硬币,如果没有的话,就是无解,因为你凑不出1元

下面我们就得列举找规律了(先不按每种面值无限张算,就按每种只有一张算):

有了面值1元,就一定要有面值2元的,不然你凑不出2元:目前面值:1元、2元

接着想,需不需要3元呢?其实是不需要的,因为1元和2元可以凑出3元;目前面值:1元、2元

那四元呢?那就必须要了,无论用前面所有的面值也凑不到4元。目前面值:1元、2元、4元

五元?可以用1元和4元凑成,不用!  目前面值:1元、2元、4元

六元?可以用2元和4元凑成,不用!  目前面值:1元、2元、4元

七元?可以用1元、2元和4元凑成,不用!  目前面值:1元、2元、4元

八元?前面三个面值怎么也凑不成,必须要用!  目前面值:1元、2元、4元、8元

以此类推会得到这样的数列:1元、2元、4元、8元、16元、32元、64元……

由次我们发现了一个规律:每新来一枚硬币,它的值只可能小于等于前面所有面值和+1

知道了贪心策略,代码就迎刃而解了!

示范代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int sum,cnt,n,x,a[1005];//sum表示目前硬币面值总和,cnt表示硬币数 
	cin>>x>>n; 
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+n+1);//从小到大排序,保证小的在前 
	//如果没有一元的硬币,就凑不出1元,所以无解 
	if(a[1]!=1) 
	{
		cout<<"-1"<<endl;
		return 0;
	}
	sum=1; cnt=1;//初始必定要一枚一元,目前sum=1,cnt=1 
	while(sum<x)//一直循环,知道能凑出最大的那个面值为止 
	{
		int p=0;//指针 
		for(int i=1;i<=n;i++) if(a[i]<=sum+1) p=i;//贪心思路 
		sum+=a[p];
	    cnt++;	
	}
	cout<<cnt<<endl;
	return 0;
}

结尾

你学会了吗?还不赶紧去试试?

对了,我是爱编程的小芒果,喜欢我的文章记得点个免费的赞哦!下次我们讲dfs深搜算法!Bye!

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱编程的小芒果

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值