算法(二)暴力枚举

一、概述

1、概念

枚举,顾名思义,就是将所有情况都举出,并判断其是否符合题目条件。所以枚举的基本方法便是分析题意后,找到一个合适的维度列举每一个元素,以完成题目。其中如何找到一个合适的维度来进行枚举便是其中的最大难点

2、枚举的基本条件

(1)时间条件

枚举范围小或时间无限制(蓝桥杯填空题)

一般来说主流的OJ当中,1000ms的时间限制下可以运行操作数为107以内的运算(通常106以内较为保险),所以在采用枚举方法之前最好看一下数据范围,确保整个程序的执行操作数不会超过106-107这个量级,如果超过了就尝试更换枚举的维度或者使用其他算法吧。

(2)编程上的实现条件

在编程实现上,一般来说暴力枚举需要两个条件,一是枚举的范围一般需要连续,如果枚举范围是离散的,那么一般很难使用for循环枚举出所有状态,也就不能保证解的完整性(不过有些时候数据看似离散,但实际上可以经过处理变得连续,如构造数组)。第二个条件是枚举内容需要已知,不能在枚举到某个地方的时候出现未知(不过这个一般都被满足)。

3、不适用的情况

(1)简单的暴力枚举一般只适用于解决简单的问题

(2)难以求出或范围特别大,明显超时(数论等)

https://www.luogu.com.cn/problem/P1403

4、解题思路

(1)找到枚举变量**(尽量由已知推未知)**

(2)找到并尽量缩小范围(根据题意但无需太过精确,可以过大,条件在if中判断即可

(3)依据题意进行操作**(尽量剪枝)**

二、数学运算问题

技巧

(1)枚举变量

按位数0-9(一),按数字(二),或离散时构造数组(一、2)

尽量由已知推未知:一般有一个变量可以直接运算得出。尽量用乘法(二、1)

(2)常见限制

位数、位数字出现次数

(3)取位方法

//取b由低到高位
for(int i = 0;b != 0;i++)
{
    a[i] = b % 10;
    b /= 10;
}

(4)记录位数字出现个数

使用数组a[10],a[i]代表数字i出现了a[i]次

(5)从小到大

从小到大枚举(一、4)

(一)按位枚举

适用于条件偏向于位

1、4个不同的数字

org[i]代表org[i]已出现

https://blog.youkuaiyun.com/weixin_38172774/article/details/87354310

2、数码管的标价

https://blog.youkuaiyun.com/weixin_38172774/article/details/87354310

思路:先找一个,然后继续找另一个

枚举变量:离散可构造数组

3、对着数字发呆

https://blog.youkuaiyun.com/weixin_38172774/article/details/87354310

4、四平方和定理

https://blog.youkuaiyun.com/weixin_38172774/article/details/87354310

从小到大:从小到大枚举

#include <iostream>
#include <math.h>

using namespace std;

int main() {
    int n,temp;
    int a,b,c;
    //注意类型!
    double d;

    cin >> n ;

    for(a = 0 ; a*a <= n; a++){
        for(b = a ; b*b <= n; b++){
            for(c = b ; c*c <= n; c++){
                d = sqrt(n-a*a-b*b-c*c);
                //判断d是否为整数!
                if(d == int(d)){
                    cout << a<<" "<<b<<" "<<c<<" "<<d;
                    //输出第一个表示法!
                    return 0;
                }
            }
        }
    }
}


5、请猜谜

https://blog.youkuaiyun.com/weixin_38172774/article/details/87354310

注意判断是否为6位数

(二)数字枚举

适用于数字x,y或数字并非刚好为临界(如1111)

1、abcde/fghij=n

https://blog.youkuaiyun.com/weixin_38172774/article/details/87354310

b/a = n得b = a * n;避免小数的出现,自然就节约判断了

可以确定:a来说最小为01234,最大为98765

2、火柴棒等式

由于题目中已经给出,最多有24根火柴,而等号和加号各用4根的前提下,A\B\C三个数则总共只有20根火柴,数据范围较小,可以用枚举法枚举A、B。这个时候我们发现,0-9这10个数字所用的火柴数为:6,2,5,5,4,5,6,3,7,6,很明显数字1用的火柴棒最少只要2根,不妨让B为1,那么A和C最多可以使用18根火柴,而C>=A,满足条件的A的最大取值为1111。所以枚举A和B的范围是从0~1111。(应该是过大了)

#include <stdio.h>
#include <stdlib.h>
int a[2223]= {6,2,5,5,4,5,6,3,7,6};//前10需要的火柴数目
const int b[10]= {6,2,5,5,4,5,6,3,7,6};//定义b数组的值,不可改变
int need(int n)
{
    int t, num;
    num=0;
    if(n==0) return 6;
    while(n>0)
    {
        t=n%10;
        num+=b[t];//统计数字并且把这些数字所需要的火柴数目加起来
        n/=10;//跳过最后一个数字
    }
    return num;
}
int main( )
{
    int n,i,j,A,B,C,D,sum;
    scanf("%d",&n);
    sum=0;
    //预处理
    for(i=10; i<2223; i++)
        a[i]=need(i);//把每个数字需要的火柴数目赋值
    for(i=0; i<=1111; i++)
    {
        for(j=0; j<=1111; j++)
        {
            A=a[i];//A的火柴数目
            B=a[j];//B的火柴数目
            C=n-4-A-B;//C的火柴数目
            D=a[i+j];//等式的实现是通过i+j=(i+j)
            if(D==C) sum++;//如果符合等式
        }
    }
    printf("%d\n",sum);
    return 0;
}
 

3、uva10976

y的范围为 k<y<2k

注意判断x是否为整数 k*y%(y-k)) == 0

https://www.cnblogs.com/rhythmic/p/5980017.html

三、模拟+暴力枚举

技巧

依据题意即可

1、机器人繁殖

https://blog.youkuaiyun.com/weixin_38172774/article/details/87354310

#include <iostream>

using namespace std;

int main() {
    int n;
    long long total,count = 0,thisYear=0,lastYear=0 ;
    cin >> n >>total;
    //暴力枚举可能的最初值
    for (int i = 1; i < total; ++i) {
        count = i; thisYear = i;
        for (int j = 0; j < n; ++j) {
            lastYear = thisYear;
            thisYear = lastYear*2-1;
            count+= thisYear;
        }
        if (count == total) {
            cout << i;
            return 0;
        } else continue;
    }
}

2、HDU1422 重温世界杯

http://acm.hdu.edu.cn/showproblem.php?pid=1422

https://www.cnblogs.com/rhythmic/p/5980017.html

哪里用到那个结论了?

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 200000 + 5;
int a[maxn];
int main()
{
     int n;
     while(scanf("%d",&n) != EOF)
     {
            //存净收入
            for(int i = 1;i <= n;i++)
            {
                  int x , y;
                  scanf("%d%d",&x,&y);
                  a[i] = x - y;
                  //拓展数组以便模拟循环!
                  a[n+i] = x - y;
            }
            int num = 0;
            int Max = 0;
            //现在的钱
            int ans = 0;
             //遍历整个数组!
             for(int i = 1;i <= 2*n;i++)
             {
                 ans += a[i];
                 if(ans >= 0)
                      num++;
                 else
                 {
                       num = 0 , ans = 0;
                 }
                 Max = max(num , Max);
                 if(Max == n) break;
             }

             printf("%d\n",Max);
     }
}

3、滑雪课程设计

对最矮进行枚举

https://www.luogu.com.cn/problem/P3650

<think>好的,我现在需要帮助用户了解C++暴力枚举算法的使用示例。首先,我应该回忆一下暴力枚举的基本概念。根据用户提供的引用内容,暴力枚举就是逐个列举所有可能的情况来寻找答案。这种方法虽然简单,但可能在处理大数据时效率不高,不过对于小规模问题很有效。 接下来,用户需要具体的示例,所以我应该考虑几个典型的应用场景。比如寻找水仙花数、鸡兔同笼问题、寻找质数等。这些都是暴力枚举常见的例子。我需要确保每个例子都符合C++的语法,并且代码简洁易懂。 首先,水仙花数的例子。水仙花数是指一个三位数,其各位数字立方和等于该数本身。比如153。这时候需要用循环遍历100到999的所有数,分解各位数字,然后判断是否符合条件。这个例子能很好展示暴力枚举的思路。 然后是鸡兔同笼问题,这是一个经典的问题,已知头数和脚数,求鸡和兔的数量。需要遍历所有可能的鸡的数量,然后计算对应的兔的数量是否符合脚数的条件。这里要注意循环的范围,比如鸡的数量最多不超过总头数,所以循环变量应该从0到总头数。 第三个例子可以是寻找质数,比如找出1到n之间的所有质数。对于每个数,检查是否有除了1和自身以外的因数。这里可以用双重循环,外层遍历每个数,内层检查是否为质数。不过要注意优化,比如内层循环只需到平方根即可,但为了保持暴力枚举的简单性,可能暂时不优化。 接下来,我需要参考用户提供的引用内容。引用[1]提到了求最大公约数的例子,但用户给的例子是找偶数,这可能不够典型。不过用户给出的例子代码结构清晰,可以借鉴循环和条件判断的结构。引用[2]强调暴力枚举就是逐个列举,所以例子需要覆盖不同情况。 在编写代码时,要确保语法正确,比如使用正确的头文件、命名空间,以及循环结构。例如,鸡兔同笼问题中,如果找到解就输出,否则输出无解。质数的例子中,需要嵌套循环,并在发现因数时标记为非质数。 另外,用户可能需要了解暴力枚举的优缺点,比如简单但效率低,适用于小数据量。因此,在回答中应提到这些点,帮助用户理解适用场景。 最后,生成相关问题,比如优化方法、适用场景、时间复杂度分析等,这样用户如果有进一步的问题,可以参考这些方向。 现在需要组织回答结构,先介绍暴力枚举的概念,再分三个示例,每个示例给出问题描述和代码,最后总结优缺点和相关问题。确保所有数学公式用$...$格式,独立公式用$$...$$,但例子中的数学可能较少,可能主要是变量如i % 2 ==0这样的表达式,需要用$包裹。</think>### C++暴力枚举算法使用示例 暴力枚举算法通过遍历所有可能情况来解决问题,适用于小规模数据场景。以下是三个典型应用示例: #### 1. 寻找水仙花数 水仙花数是满足$abc = a^3 + b^3 + c^3$的三位数($100 \leq n \leq 999$) ```cpp #include <iostream> using namespace std; int main() { for (int n = 100; n <= 999; n++) { int a = n / 100; int b = (n / 10) % 10; int c = n % 10; if (a*a*a + b*b*b + c*c*c == n) { cout << n << " "; } } return 0; } // 输出结果:153 370 371 407 ``` #### 2. 鸡兔同笼问题 已知总头数$h=35$,总脚数$f=94$,求鸡兔数量: $$ \begin{cases} x + y = h \\ 2x + 4y = f \end{cases} $$ ```cpp #include <iostream> using namespace std; void solve(int h, int f) { bool found = false; for (int x = 0; x <= h; x++) { // x为鸡的数量 int y = h - x; // y为兔的数量 if (2*x + 4*y == f) { cout << "鸡:" << x << " 兔:" << y << endl; found = true; } } if (!found) cout << "无解" << endl; } int main() { solve(35, 94); // 输出:鸡:23 兔:12 return 0; } ``` #### 3. 质数筛选 找出1到$n$之间的所有质数: ```cpp #include <iostream> using namespace std; bool is_prime(int num) { if (num <= 1) return false; for (int i = 2; i < num; i++) { if (num % i == 0) return false; } return true; } int main() { int n = 50; for (int i = 2; i <= n; i++) { if (is_prime(i)) { cout << i << " "; } } return 0; } // 输出结果:2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 ``` ### 算法特性 | 特性 | 说明 | |------------|-------------------------------| | 时间复杂度 | $O(n)$到$O(n^2)$ | | 空间复杂度 | 通常为$O(1)$ | | 优点 | 实现简单,逻辑清晰 | | 缺点 | 数据量大时效率急剧下降[^2] |
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值