c/c++编程中最常用的算法-穷举搜索(代码片段)

cpp_learner cpp_learner     2023-01-09     471

关键词:

算法中,最常用的应该就是穷举搜索算法了吧,也许你已经使用过了,只是自己不知到而已!


讲述一道题目,你就会知道什么是穷举算法了!

我国古代数学家张丘建在《算经》一书中曾提出过著名的“百钱买百鸡”问题,该问题叙述如下:
鸡翁一,值钱五;鸡母一,值钱三;鸡雏三,值钱一;百钱买百鸡,则翁、母、雏各几何?
上题的意思是公鸡一只五块钱,母鸡一只三块钱,小鸡三只一块钱,现在要用一百块钱买一百只鸡,问公鸡、母鸡、小鸡各多少只?

题目已经给出了,看着题目,你能想到的最简单的解决办法是什么?
是不是将全部结果都判断一次,然后超出符合条件的就可以了!

所以代码如下:

int main(void) 
	int fChook = 0;			// 公鸡数量
	int mChook = 0;			// 母鸡数量
	int litleChook = 0;		// 小鸡数量
	
	int count1 = 0;		// 统计循环次数

	for (fChook = 0; fChook <= 20; fChook++) 
		for (mChook = 0; mChook <= 33; mChook++) 
			for (litleChook = 3; litleChook <= 99; litleChook += 3) 
				count1++;
				if ((fChook * 5 + mChook * 3 + litleChook / 3) == 100 && (fChook + mChook + litleChook) == 100) 
					cout << "公鸡:" << fChook << ",母鸡:" << mChook << ",小鸡:" << litleChook << endl;
							
			
		
	

	//cout << "未优化循环次数:" << count1 << endl;
	return 0;

为什么第一个for循环判断条件是小于等于20?
因为一只公鸡5元钱,5乘以20就刚好等于100元了,所以公鸡的数量不能超过20只。

为什么第二个for循环判断条件是小于等于33?
因为一只母鸡3元钱,3乘以33等于99元,所以母鸡的数量不能超过33只。

为什么第三个for循环判断条件是小于等于99?
小鸡三只1元钱,99除以3等于33元,且99只小鸡已经是顶峰了,因为不能单独买一只小鸡。

运行截图:

可以看到,不管怎么算都是正确的!

上面的代码,就是穷举搜索算法!

穷举法(枚举法)的基本思想是:

  1. 列举出所有可能的情况,逐个判断有哪些是符合问题所要求的条件,从而得到问题的全部解答。
  2. 它利用计算机运算速度快、精确度高的特点,对要解决问题的所有可能情况,一个不漏地进行检查,从中找出符合要求的答案。

用穷举算法解决问题,通常可以从两个方面进行分析:
(1)问题所涉及的情况:问题所涉及的情况有哪些,情况的种数必须可以确定。把它描述出来。应用穷举时对问题所涉及的有限种情形必须一一列举,既不能重复,也不能遗漏。重复列举直接引发增解,影响解的准确性;而列举的遗漏可能导致问题解的遗漏。
(2)答案需要满足的条件:分析出来的这些情况,需要满足什么条件,才成为问题的答案,把这些条件描述出来。

那他这样到底循环判定了多少次呢?还是上面那一套代码,将注释那行代码解开注释,再一次运行:

天呐!运行了两万多次,要不是我点的CUP还可以,这不得卡死?
不行,这代码绝对不行,我们来看看还有没有可以优化的地方!

这当然有!

就是当公鸡达到一定数量时,母鸡就无需判断那么多次了;当母鸡达到一定数量时,小鸡就无需判断那么多次了!
接着这个思路,我们来写优化代码。

优化后的代码如下:

int main(void) 
	int fChook = 0;			// 公鸡数量
	int mChook = 0;			// 母鸡数量
	int litleChook = 0;		// 小鸡数量

	int count1 = 0;
	int count2 = 0;

	for (fChook = 0; fChook <= 20; fChook++) 
		for (mChook = 0; mChook <= 33; mChook++) 
			for (litleChook = 3; litleChook <= 99; litleChook += 3) 
				count1++;
				if ((fChook * 5 + mChook * 3 + litleChook / 3) == 100 && (fChook + mChook + litleChook) == 100) 
					cout << "公鸡:" << fChook << ",母鸡:" << mChook << ",小鸡:" << litleChook << endl;
							
			
		
	

	cout << endl << "-----------------华丽的分割线------------------" << endl << endl;

	/* 通过钱的总数控制 */
	for (fChook = 0; fChook <= 20; fChook++) 
		for (mChook = 0; mChook <= (100 - fChook * 5) / 3; mChook++) 
			for (litleChook = 3; litleChook <= (100 - (fChook * 5 + mChook * 3)) * 3; litleChook += 3) 
				count2++;
				if ((fChook * 5 + mChook * 3 + litleChook / 3) == 100 && (fChook + mChook + litleChook) == 100) 
					cout << "公鸡:" << fChook << ",母鸡:" << mChook << ",小鸡:" << litleChook << endl;
				
			
		
	

	cout << endl << "未优化循环次数:" << count1 << ",优化后循环次数:" << count2  << endl;

	return 0;

代码中,我是通过钱来控制剩下两个for循环的判断条件的。
第二个for循环,(100 - fChook * 5) / 3,先拿一百块钱减去当前公鸡数量所花费的钱,剩下的钱再除以一只母鸡的价格,那么就可以得到母鸡最多可以买多少只了。
第三个for循环也是一样的思路,一百元减去当前公鸡数量所花费的钱和母鸡数量所花费的钱,剩下来的钱,再乘以三(小鸡一只三元),就可以得到小鸡还可以再买多少只了!


看到没有,优化后循环次数是一万两千多次,这效率瞬间提升了一半,这不得起飞?

当然,因该也还有其它的优化思路,这就得大家发动脑筋思考啦!

所以,大家懂了吧,即使是遍历全部结果,也还是有优化的空间的,这穷举算法也是不错的!(用最简单的办法,找出所需要的结果)


学会了这个用法,我们来做一道简单的练习题。

有 20 枚硬币,可能包括 4 种类型:1 元、5 角、1 角和 5 分。
已知 20 枚硬币的总价值为 10 元,求各种硬币的数量。

例如:4、11、5、0 就是一种方案。而 8、2、10、 0 是另一个可能的方案,显然方案并不是唯一的,请编写程序求出类似这样的不同的方案一共有多少种?
(1)编程思路。
直接对四种类型的硬币的个数进行穷举。其中,1 元最多 10 枚、5 角最多 20 枚、1 角最多 20 枚、5 分最多 20 枚。

开始写代码吧
如果以元为单位,则 5 角、1 角、5 分会化成浮点型数据,容易计算出错。可以将 1元、5 角、1 角、5 分变成 100 分、50 分、10 分和 5 分,从而全部采用整型数据处理!

做法和思路跟上面类似,我就直接将代码列举出来了!

#include <iostream>
#include <string>

using namespace std;

int main(void) 
	int a100 = 0;	// 1元的硬币数量
	int a50 = 0;	// 5角的硬币数量
	int a10 = 0;	// 1角的硬币数量
	int a5 = 0;		// 5分的硬币数量
	int count = 0;	// 记录可行的方案总数

	int count1 = 0;
	int count3 = 0;

	for (a100 = 0; a100 <= 10; a100++) 
		for (a50 = 0; a50 <= 20; a50++) 
			for (a10 = 0; a10 <= 20; a10++) 
				for (a5 = 0; a5 <= 20; a5++) 
					count1++;
					if ((a100 * 100 + a50 * 50 + a10 * 10 + a5 * 5) == 1000 && (a100 + a50 + a10 + a5) == 20) 
						cout << "1元硬币:" << a100 << "枚, 5角硬币:" << a50 << "枚, 1角硬币:" << a10 << "枚, 5分硬币:" << a5 << "枚!" << endl;
						count++;
					
				// a5 end.
			// a10 end.
		// a50 end.
	// a100 end.

	cout << "一共有:" << count << "种组合!" << endl;
	count = 0;


	cout << endl << "-----------------华丽的分割线------------------" << endl << endl;

	/* 通过硬币数量控制 */
	for (a100 = 0; a100 <= 10; a100++) 
		for (a50 = 0; a50 <= (20 - a100); a50++) 
			for (a10 = 0; a10 <= (20 - a100 - a50); a10++) 
				for (a5 = 0; a5 <= (20 - a100 - a50 - a10); a5++) 
					count3++;
					if ((a100 * 100 + a50 * 50 + a10 * 10 + a5 * 5) == 1000 && (a100 + a50 + a10 + a5) == 20) 
						cout << "1元硬币:" << a100 << "枚, 5角硬币:" << a50 << "枚, 1角硬币:" << a10 << "枚, 5分硬币:" << a5 << "枚!" << endl;
						count++;
					
				// a5 end.
			// a10 end.
		// a50 end.
	// a100 end.


	cout << "一共有:" << count << "种组合!" << endl;

	cout << endl << "未优化循环次数:" << count1 << ",优化后循环次数:" << count3 << endl;

	return 0;


总结

其实这个穷举搜索算法大家都会使用,重点是理解它的思路和过程;知道怎么去优化就可以的了!

c/c++并行搜索算法(代码片段)

...概念所谓并发是在同一实体上的多个事件同时发生。并发编程是指在在同一台计算机上“同时”处理多个任务。其实也就是多个工人共同工作,提高工作效率!并行搜索算法,就是有一组特别大的数据,需要在这... 查看详情

c/c++并行搜索算法(代码片段)

...概念所谓并发是在同一实体上的多个事件同时发生。并发编程是指在在同一台计算机上“同时”处理多个任务。其实也就是多个工人共同工作,提高工作效率!并行搜索算法,就是有一组特别大的数据,需要在这... 查看详情

常用算法-穷举法

...又称为枚举法,它是在计算机算法设计中用得最多的一种编程思想。它的实现方式是:在已知答案范围的情况下,依次地枚举该范围内所有的取值,并对每个取值进行考查,确定是否满足条件。经过循环遍历之后,筛选出符合要... 查看详情

六中常用算法设计:穷举法分治法动态规划贪心法回溯法和分支限界法(代码片段)

算法设计之六种常用算法设计方法1.直接遍历态(穷举法)      程序运行状态是可以遍历的,遍历算法执行每一个状态,最终会找到一个最优的可行解;适用于解决极小规模或者复杂度线性增长,而线... 查看详情

chatgpt教你算法——常用的图搜索算法(代码片段)

0.引言这一次我们将会介绍常用的图搜索算法,分别BFS广度优先搜索和DFS深度优先搜索。1.图搜索算法介绍常用的图搜索算法包括广度优先搜索(BFS)和深度优先搜索(DFS)。广度优先搜索(BFS)是一种... 查看详情

学习java绝对要懂的,java编程中最常用的几种排序算法!

今天给大家分享一下Java中几种常见的排序算法的Java代码推荐一下我的Java学习羊君前616,中959,最后444.把数字串联起来!  ,群里有免费的学习视频和项目给大家练手。大神有空时也会带带大家的,学Java的过程中一定要... 查看详情

c/c++算法基础(代码片段)

...介绍与算法密切相关的技术问题。本文的重点是通过一些编程实例介绍程序设计中常用的思想方法和实现手段,不侧重介绍某种高级程序设计语言的语法细节。在这一章里,我们对将要使用的C/C++语言的相关内容做... 查看详情

c/c++算法基础(代码片段)

...介绍与算法密切相关的技术问题。本文的重点是通过一些编程实例介绍程序设计中常用的思想方法和实现手段,不侧重介绍某种高级程序设计语言的语法细节。在这一章里,我们对将要使用的C/C++语言的相关内容做... 查看详情

chatgpt教你算法——常用的图搜索算法(代码片段)

0.引言这一次我们将会介绍常用的图搜索算法,分别BFS广度优先搜索和DFS深度优先搜索。1.图搜索算法介绍常用的图搜索算法包括广度优先搜索(BFS)和深度优先搜索(DFS)。广度优先搜索(BFS)是一种... 查看详情

常用的排序算法(代码片段)

...大排序算法选择排序思路选择排序应该是这么多排序算法中最简单的一种排序算法了,主要思路是找到数组中最小的元素,其次,将它和数组的第一个元素交换位置(如果第一个元素就是最小的元素就和自己交换)。再次,在剩... 查看详情

万能的搜索--之简介

...到部分的分数。*搜索,严格说不上是一个算法,是一种编程的思路:通过穷举所有的可能性,我们模拟问题的处理步骤,直到找到问题的解。*穷举所有的可能性就注定了时间和空间花销肯定会很大,所以一般只有在数据范围较... 查看详情

算法竞赛常用知识(代码片段)

上一篇博客:蓝桥杯第六届C/C++B组真题详解 写在前面:大家好!我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正,感谢大家的不吝赐教。我的唯一博客更新地址是:https:... 查看详情

六中常用算法设计:穷举法分治法动态规划贪心法回溯法和分支限界法(代码片段)

算法设计之六种常用算法设计方法1.直接遍历态(穷举法)      程序运行状态是可以遍历的,遍历算法执行每一个状态,最终会找到一个最优的可行解;适用于解决极小规模或者复杂度线性增长,而线... 查看详情

常用编程思想与算法

...,对基础算法感兴趣的朋友可以阅读原文。由于本人也是编程初学者,所以本书比较浅显易懂,所介绍的算法配上插图也十分易懂,这里只是介绍几种最基础的算法由浅入深以帮助理顺一些简单的思维逻辑。算法简介  算法是... 查看详情

简单算法复习(代码片段)

个人认为,信息学竞赛中最难的部分,要数算法的学习和灵活运用了吧。其实算法呢,讲讲概念很好理解,可一道题目中,就千变万化,纯看个人造诣了。本人在这方面比较弱。。。讲的太浅显,或者有什么问题还请不吝赐教。... 查看详情

《英雄编程体验课》第12课|递归

文章目录零、写在前面一、搜索算法的原理二、深度优先搜索三、基于DFS的记忆化搜索四、基于DFS的剪枝五、基于DFS的A*(迭代加深,IDA*)零、写在前面  该章节节选自《夜深人静写算法》,主要讲解最基础的搜索算法,其中... 查看详情

五大经典算法之回溯法(代码片段)

...,就会退回一步重新选择,这种达不到目的就退回再走的算法称为回溯法。与穷举法的区别和联系:相同点:它们都是基于试探的。区别:穷举法要将一个解的各个部分全部生成后,才检查是否满足条件,若不满足,则直接放弃... 查看详情

函数式编程(random)(代码片段)

如果你对在Python生成随机数与random模块中最常用的几个函数的关系与不懂之处,下面的文章就是对Python生成随机数与random模块中最常用的几个函数的关系,希望你会有所收获,以下就是这篇文章的介绍。random.random()用于生成用于... 查看详情