【算法】枚举算法

目录

算法详述

例题

A - 火柴棒等式

B - 砝码称重

输入格式

输出格式


算法详述

枚举:即对可能的解集合一一列举。 

枚举算法的实现往往通过使用循环(嵌套)就能够轻易实现,所以并没有什么思维难度。

解题思路:

1. 对解的每个参数的数据范围采用循环语句一一枚举,对每次枚举采用if语句判断是否是解以及是否是最优解。

枚举小技巧:

1. 有时候,我们枚举的东西如果满足一个公式,我们的循环可以少写一层,优化效率。比如如果枚举A+B+C=100,我们只需要枚举A和B,C可以直接用100-A-B,这样就少一层循环。

2. 当然,改变枚举的顺序也是一种小技巧。一般都是从小到大或者从大到小,但是还有其他顺序,这就用到了贪心算法。

3. 有时候我们需要枚举的是每个东西的状态(一般为两种状态),我们可以用二进制里面的0/1来表示这两种状态来进行枚举。比如(二进制枚举)有5个小朋友,枚举他们是否看过该博客,这时候可以把看过或者没有看过表示两种状态,分别用0和1表示。现在给数字5,二进制是101,说明第1和第3个小朋友看过。所以我们可以枚举0~2^{5}-1(31)来表示5个小朋友每个小朋友之间的状态是什么。

4. 有时候,我们枚举的故率达不到题目所需,我们就可以将枚举出来的所有结果事先保存下来,然后在第二份程序里直接调用,这就是打表的思想。

5. 还有时候,简单的循环嵌套可能满足不了我们的需求,可以考虑递归算法实观。
 

例题

A - 火柴棒等式

给你 nn 根火柴棍,你可以拼出多少个形如 "A+B=C" 的等式?等式中的 A、B、C 是用火柴棍拼出的整数(若该数非零,则最高位不能是 0)。

用火柴棍拼数字 0-9,0−9 的拼法如图所示

注意:

  1. 加号与等号各自需要两根火柴棍

  2. 如果 A\neq B,则A+B=C与B+A=C 视为不同的等式(A、B、C ≥0)

  3. n 根火柴棍必须全部用上

输入格式

输入一个整数 n(n≤24)。

输出格式

输出能拼成的不同等式的数目。

Sample Input

5

 Sample Output

 0

分析:

(1)0~9所需要的火柴数:6,2,5,5,4,5,6,3,7,6 根火柴

(2)因为+=一共是4根,所以最后火柴数需要加上4

(3)因为1是所有数字中所用火柴数最少的数字,1111是四位数中最大的数,而且1111+1=1112此时一共25根>24,所以基本上不会到达四位数,因此最后循环到1000即可。由于担心某种特殊情况没有考虑到,可以将a数组放大到2000

(4)首先需要一个数组存放0~2000苏需要的火柴数,即数组a。然后求a[i]+a[j]+a[i+j]+4的火柴数,如果该数=n则让s加1并且继续循环,直到全部循环完成即可。

(5)其中11111问题的解析:关于《啊哈!算法》第三章火柴棍等式“1111”问题的解析_BDICOMENOW的博客-CSDN博客

代码 :

#include<iostream>
using namespace std;
int main()
{
	int a[2001] = { 6 }, n, c[10] = { 6,2,5,5,4,5,6,3,7,6 }, s = 0, i, j;
	//a数组表示下标所需要的火柴数,a[0]=6,其他的是0;n即输入的n的大小;其中c数组存储0~9数字所需要的火柴数
	cin >> n;
	for (i = 1; i <= 2000; i++)//因为1111是四位数用的最少的数,1111+1=1112此时就25根棍子了,所以基本上就不会实现四位数,但是把上界稍微放大了
	{
		j = i;
		while (j >= 1)//将数字进行十进制的拆分,将i所需要的火柴数放入a数组中
		{
			a[i] = a[i] + c[j % 10];
			j = j / 10;
		}
	}
	for (i = 0; i <= 1000; i++)//求出该等式所需要的火柴棍
	{
		for (j = 0; j <= 1000; j++)
			if (a[i] + a[j] + a[i + j] + 4 == n)//+4是因为+和=一共需要四根火柴棍
				s++;//s表示符合要求的答案数
	}
	cout << s;
	return 0;
}

B - 砝码称重

设有 1g,2g,3g,5g,10g,20g的砝码各若干枚(其总重小于等于 1000),现在求问这些砝码能称出多少不同的重量。

输入格式

一行六个整数,分别代表 1g 砝码的个数,分别代表 2g砝码的个数,分别代表 3g 砝码的个数,分别代表 5g 砝码的个数,分别代表 10g 砝码的个数,分别代表 20g 砝码的个数。

输出格式

输出一行,格式为 Total=n。

(n 表示用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况)

Sample Input

1 1 0 0 0 0  

Sample Output 

Total=3

分析:

此题最好是可以用到枚举小技巧3,具体代码可见:(42条消息) B - 砝码称重_bairimeng16的博客-CSDN博客

代码: 

#include <iostream>
using namespace std;

int main() {
	int h[1005] = { 0 }, cm[7];                                    // 9018最奇怪的一点,重量必须是1004以下,否则会WA 
	for (int i = 1; i <= 6; i++) cin >> cm[i];
	for (int a = 0; a <= cm[1]; a++)                                // 枚举个数 
		for (int b = 0; b <= cm[2]; b++)
			for (int c = 0; c <= cm[3]; c++)
				for (int d = 0; d <= cm[4]; d++)
					for (int e = 0; e <= cm[5]; e++)
						for (int f = 0; f <= cm[6]; f++) {
							h[a + 2 * b + 3 * c + 5 * d + 10 * e + 20 * f] = 1;        // 重量桶 
						}
	int sum = 0;
	for (int i = 1; i <= 1004; i++) if (h[i]) sum++;
	cout << "Total=" << sum << endl;
	return 0;
}

  • 14
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值