这几天刷的算法好几次都提到了枚举法,虽然很早知道这个词,但是对枚举的概念是迷迷糊糊的,今天特意查了一下。
枚举法,也称为列举法、穷举法,是暴力策略的具体体现,又称为蛮力法。
枚举法的基本思想是: 逐一列举问题所涉及的所有情形,并根据问题提出的条件检验哪些是问题的解,哪些应予排除。
枚举模式:
1)区间枚举
对于有明确范围要求的实际案例,通过枚举循环的上下限控制枚举区间,而在循环体中完成各个运算操作,然后根据所求解的具体条件,应用选择结构实施判别与筛选,求得所要求的解。
n = 0
for(k = 区间下限;k <= 区间上限;k++){
运算操作序列
if(约束条件){
System.out.println(满足要求的解);
n++;
}
}
System.out.println(解的个数);
2) 递增枚举
有些问题没有明确的范围限制,可根据问题的具体情况试探性地从某一起点开始增值枚举,对每个数进行操作与判别,若满足条件则输出结果;
k = 0;
while(true){
k++;
运算操作序列
if(约束条件){
System.out.println(满足要求的解);
return;
}
}
枚举的意义:
1) 可以充分利用计算机的速度,解决一些常见问题
2) 如果问题的规模不大,使用枚举,运算速度是可以接收的。
3) 枚举可作为某类问题时间性能的底线,用来引出同样问题的更高效率的算法。
枚举的实施步骤:
1) 根据问题的具体情况确定枚举量(简单变量或数组)
2) 根据问题的具体清空确定枚举范围,设置枚举循环
3) 根据问题的具体要求确定筛选(约束)条件
4) 设计枚举程序并运行、调试,对运行结果进行分析与讨论。
比如:
使用枚举法解决“填写运算符问题”
1,问题描述:在下面的算式中,添加“+”、“-”,“*”,“/”,4个运算符,使得这个式子成立。
5 5 5 5 5=5
2,算法分析:
上述式子左侧有5个数字,一共需要4个运算符。根据题目要求,两个数字之间的运算符只能有4中选择。在 具体编程时,可以通过循环来填入各种运算符,然后再判断算式左侧的值是否等于右侧的值。并保证,当填入的 是除号时,则右侧的数不能为0,并且乘除的优先级高于加减的优先级。
#include<iostream>
int main()
{
int j, i[5]; // 循环变量,数组i用来表示4个运算符
int sign; // 累加运算时的符号;
int result; // 保存运算式子的结果值
int count=0; // 计数器,统计符合条件的方案
int num[6]; // 保存操作数
float left, right; //保存中间结果
char oper[5] = { ' ','+','-','*','/' }; //运算符
printf("输入5个数,之间用空格隔开:");
for (j = 1; j <= 5; j++)
scanf_s("%d",&num[j]);
printf("输入结果:");
scanf_s("%d",&result);
//注:这里i[1]代表的第一个运算符的意思,i[1]=1代表第一个运算符是“+”,i[1]=2代表第一个运算符是“减”,i[1]=3代表第一个运算符是“-”,i[1]=4代表第一个运算符是“/”
//注:这里i[2]代表的第二个运算符的意思,i[2]=1代表第二个运算符是“+”,i[2]=2代表第二个运算符是“减”,i[2]=3代表第二个运算符是“-”,i[2]=4代表第二个运算符是“/”
//i[3],i[4]依次类推。
for (i[1]=1; i[1]<=4; i[1]++) //循环4种运算符,1表示+,2表示-,3表示*,4表示/
{
if ((i[1]<4) || (num[2] != 0)) //运算符若是/,则第二个运算数不能为0,(注:“||”是或运算,两个条件至少要有一个成立,即第一个运算符为/时,第二个运算数不为0)
{
for (i[2]=1; i[2]<=4; i[2]++)
{
if ((i[2]<4)||(num[3]!= 0)) //当第二个运算符为/时,第三个运算数不为0
{
for (i[3] = 1; i[3] <= 4; i[3]++)
{
if ((i[3] < 4) ||( num[4] != 0)) //当第三个运算符为/时,第四个运算数不为0
{
for (i[4] = 1; i[4] <= 4; i[4]++)
{
if ((i[4] < 4) || (num[5] != 0)) //当第四个运算符为/时,第五个运算数不为0
{
left = 0;
right = num[1];
sign = 1;
//使用case语句,将4种运算符填到对应的空格位置,并进行计算
for (j = 1; j <= 4; j++)
{
switch (oper[i[j]])
{
case '+':
left = left + sign*right;
sign = 1;
right = num[j + 1];
break;
case '-':
left = left + sign*right;
sign = -1;
right = num[j + 1];
break;
case '*':
right = right*num[j + 1];
break;
case '/':
right = right / num[j + 1];
break;
}
}
//开始判断,如果运算式子的结果和输入的结果相同,则表示找到一种算法,并输出这个解
if (left + sign*right == result)
{
count++;
printf("%3d:",count);
for (j = 1; j <= 4; j++)
printf("%d%c",num[j],oper[i[j]]);
printf("%d=%d\n",num[5],result);
}
}
}
}
}
}
}
}
}
if (count == 0)
printf("没有符合要求的方法!\n");
system("pause");
return 0;
}
运行结果: