蛮力法详解

前言

蛮力法(Brute Force)是一种简单直接的问题求解方法,其基本思想是通过穷举所有可能的解决方案,逐一检查每个解决方案是否满足问题的要求,最终找到符合条件的解决方案。

在计算机科学领域,蛮力法常用于解决一些简单、规模较小的问题,或作为解决复杂问题的一部分。虽然蛮力法的效率通常较低,但由于其简单易懂的特点,它常被用于问题的验证和算法的初步设计。

蛮力法的实现往往涉及到使用循环、嵌套循环和条件判断等基本控制结构,以遍历所有可能的解空间。在每个可能的解决方案上,我们根据问题的要求进行判断,确定是否为可行解或最优解。

然而,需要注意的是,蛮力法并不是解决所有问题的最优解决方案。对于规模非常大的问题,蛮力法的时间复杂度可能会变得非常高,导致计算成本过大。因此,在实际应用中,我们通常会尝试寻找更高效的算法来解决问题。

   

一、蛮力法是什么?

蛮力法是一种朴素、直接的问题求解方法,适用于一些简单问题和初步算法设计。

1.1蛮力法基本思想

基于问题的描述与定义,尝试该问题的所有可能的解,并逐一进行测试,如果不可行,就尝试下一种解法,直到找出可行解为止。


1.2蛮力法的特点

1.蛮力法特点是简单直接且容易实现,“力”指的是计算机的计算能力(算力)。

2.蛮力法适应力强,是一种几乎所有问题都能解决的算法。


1.3蛮力法的解题格式

使用蛮力法来设计算法时,一般使用循环语句和选择语句,循环语句用来列举所有可能的解;选择语句用来判断这个节是否满足指定的条件。

for(循环变量x的取值是所有可能的解)

{

……

    if(x满足指定的条件)

                 对x进行操作;

……

}
 

二、蛮力法的应用

2.1顺序查找


2.1.1   基本思路

顺序查找(Sequential Search),也称为线性查找,是一种简单直接的搜索算法,用于在一个元素集合中按顺序逐个查找目标元素。其基本思路如下:

  1. 从集合的第一个元素开始,逐个比较每个元素与目标元素是否相等。
  2. 如果当前元素与目标元素相等,则找到了目标元素,算法结束。
  3. 如果遍历完整个集合仍未找到目标元素,则表示目标元素不存在于集合中。


2.1.2   算法设计

    (1)、功能:在给定数组a中擦汗找数据元素k

    (2)、输入:给定数组a[0~n-1],数组中的元素n,待查找的数据元素k

    (3)、输出:数据k在数组a中的位置

#include<iostream>
int Search(int a[], int n, int k)
{
	int i = 0;
	while (i < n && a[i] != k)
		i++;
	if (a[i] == k)
		return i;
	else
		return -1;
}
int main()
{
	int a[10] = { 12,15,26,37,55,81,67,29,99,121 };
	int k = 121;
	int i;
	if ((i = Search(a, 10, k)) != -1)
		printf("查找成功,该数据元素的位置为%d", i);
	else
		printf("查找失败!");
	return 0;
}


2.1.3   算法效率分析

    (1)、输入规模:序列元素个数n

    (2)、基本操作:比较操作a[i]!=k

    (3)、算法的时间复杂度:O(n)


2.2冒泡排序

2.2.1   基本思路

冒泡排序(Bubble Sort)是一种简单直观的排序算法,它的基本思路是通过不断交换相邻元素的位置,将较大的元素逐渐“冒泡”到数组的末尾。其具体过程如下:

  1. 比较相邻的两个元素,如果第一个比第二个大,则交换这两个元素的位置。
  2. 对每一对相邻元素作同样的比较和交换,从开始的第一对到结尾的最后一对。经过这一步骤,数组的最后一个元素应该是最大的元素。
  3. 针对所有未排序的元素重复以上步骤,直至整个数组排序完成。


2.2.2   算法设计

    (1)、功能:用冒泡排序给定数组a进行排序

    (2)、输入:待排序数组a,数组中元素的个数n

    (3)、输出:按升序排序的数组a

​
#include<iostream> //包含输入输出头文件
#include<cmath>
using namespace std; //指定名字空间
int main() 
{ //主函数
	int a[100]; //定义数组,大小100
	int N; //元素的实际个数
	int i = 0, j = 0; //循环变量,并进行初始化
	cin >> N; //输入元素个数
			  //-------输入数据-----------
	for (i = 0; i<N; i++) //输入N个元素
		cin >> a[i]; //循环体只有一行
					 //-------排序---------------
	for (i = 0; i<N - 1; i++) { //控制n-1趟冒泡
		for (j = 0; j<N - 1 - i; j++)
		{
			if (a[j]>a[j + 1]) { //比较相邻的两个元素
				int tmp; //临时变量
				tmp = a[j]; //交换
				a[j] = a[j + 1];
				a[j + 1] = tmp;
			}
		}
	}
	//--------输出----------
	for (i = 0; i<N; i++) 
	{ //使用循环,输出N个元素
		cout << a[i] << " "; //输出a[i], 后加空格,不换行
	}
	cout << endl; //所有元素输出完之后才换行
	return 0; //函数返回
}

​

2.2.3   算法效率分析 

    (1)、输入规模:序列元素个数n

    (2)、基本操作:交换a[j]和a[j+1]

    (3)、算法的时间复杂度:O(n^2)


2.3直接选择排序

2.3.1   基本思路

直接选择排序(Selection Sort)是一种简单直接的排序算法,它的基本思路是在未排序的部分中选择最小(或最大)的元素,然后将其放到已排序部分的末尾。具体过程如下:

  1. 在未排序序列中,找到最小(或最大)的元素,记作最小元素。
  2. 将最小元素与未排序序列的第一个元素交换位置,即将最小元素放到已排序部分的末尾。
  3. 然后将已排序部分的末尾向后移动一位,继续从未排序序列中选择最小(或最大)的元素,重复以上步骤,直至排序完成。


2.3.2   算法设计

    (1)、功能:用直接选择排序给定数组a进行排序

    (2)、输入:待排序数组a,数组中元素的个数n

    (3)、输出:按升序排序的数组a

#include <iostream>
 
using namespace std;
 
void print(int a[], int n )
{  
	cout<<n <<":";  
	for(int j= 0; j<n; j++)
      {  
		cout<<a[j] <<" ";  
	}  
	cout<<endl;  
}  
void InsertSort(int a[], int len)  
{  
	for (int i=0; i<len-1; i++)  
	{  
		int k = i;  
		int key = a[i];  
		for (int j=i+1; j<len; j++)  //找出剩余数据中最小的数
		{  
			if (a[j]< key)  
			{  
				k = j;  
				key = a[j];  
			}  
		}  
		if (k!=i)  
		swap(a[i], a[k]);  
	}  
}  
int main(){  
	int a[9] = {3,1,5,7,2,4,9,6,6};  
	InsertSort(a,9);  
	print(a,9);  
}  


2.3.3   算法效率分析

    (1)、输入规模:序列元素个数n

    (2)、基本操作:交换a[j]<a[min]

    (3)、算法的时间复杂度:O(n^2)


2.4直接插入排序

2.4.1   基本思路

直接插入排序(Insertion Sort)是一种简单直观的排序算法,它的基本思路是将未排序的元素按照大小插入到已排序序列中的合适位置。其具体过程如下:

  1. 将第一个元素看作已排序序列,第二个元素到最后一个元素看作未排序序列。
  2. 从未排序序列中依次取出一个元素,将其插入到已排序序列的合适位置,使得插入后仍满足有序性。
  3. 重复步骤2,直至所有元素均排序完毕。

2.4.2   算法设计

    (1)、功能:用直接插入排序给定数组a进行排序

    (2)、输入:待排序数组a【0~n~1】,数组中元素的个数n

    (3)、输出:按升序排序的数组a[0~n~1]

#include<iostream>
using namespace std;
int main() {
	int a[6] = { 2, 6, 5, 3, 4, 1};
	int temp, i, j;
	int n = 6;
	for (i = 1; i < 6; i++) {  // 数组的下标是从0开始的
		// 这里从第二个数开始枚举  即假定第一个数是有序的
		temp = a[i]; j = i;     // 这里temp 临时储存每一次需要排序的数
		while (j >= 1 && temp < a[j - 1]) {
			a[j] = a[j - 1];
			j--;
		}
		a[j] = temp;
	}
	for (i = 0; i < 6; i++) {
		cout << a[i] << " ";
	}
	cout << endl;
	return 0;
}

2.4.3   算法效率分析

    (1)、输入规模:序列元素个数n

    (2)、基本操作:交换a[j+1]<a[j]

    (3)、算法的时间复杂度:O(n^2)

三、蛮力法的分析与设计

3.1蛮力法算法设计步骤

  1. 确定问题的输入和输出:首先,确定问题的输入和输出。问题的输入是指需要被处理的数据,问题的输出是指算法的结果。在使用蛮力法时,输入和输出应该清晰明确,以便能够正确地执行算法。
  2. 枚举所有可能的解:蛮力法的核心思想是枚举所有可能的解,对每个解进行评估,然后选择最优解。因此,需要根据问题的特点,列出所有可能的解,即确定搜索空间。可以使用循环、递归等方法,穷举所有可能的解。
  3. 对每个解进行评估:在枚举所有可能的解时,需要对每个解进行评估,以判断其是否符合题目要求。评估的方法通常是计算解的值,并与预期值进行比较。如果解符合要求,则将其保存为当前最优解。
  4. 选择最优解:在对所有解进行评估之后,需要从中选择最优解。最优解通常是满足问题要求的解中值最小或最大的解。可以使用一个变量来保存当前最优解,然后在每次评估时更新该变量。
  5. 实现算法:根据以上步骤,实现算法。根据问题的特点和具体需求,选择合适的数据结构、循环结构等,对算法进行完整的实现。
  6. 分析算法复杂度:在设计算法时,需要考虑算法的运行效率。因此,在实现算法之后,需要对算法的复杂度进行分析,包括时间复杂度、空间复杂度等。这些分析可以帮助我们了解算法的效率,找到需要改进的地方。

3.2百钱百鸡

鸡翁一,值钱五;鸡母一,值钱三;鸡雏三,值钱一;百钱买百鸡,则翁、母、雏各几何?

列举解的范围:z=100-x-y

约束条件:5x+3y+z/3=100&&z%3==0

# include <stdio.h>
int main()
{
	int x,y,z;//x为公鸡,y为母鸡,z为小鸡
	for(x=0;x<100;x++)
		for(y=0;y<100;y++)
			for(z=0;z<100;z+=3){
				if(x+y+z==100&&5*x+3*y+z/3==100){
					printf("公鸡:%d只  母鸡:%d只  小鸡:%d只\n",x,y,z);
				}
			}
			
    
    return 0;
}


3.3解数字谜

解数字谜,找出一个五位数符合以下竖式的条件,输出该五位数和结果的六位数。

#include<stdio.h>

int main()
{
    int A, B, C, D;
    int E, F;
    for (A = 3; A <= 9; A++)         //A的取值范围为3~9
    {
        for (D = 1; D <= 9; D++)
        {
            //将DDDDDD用E来表示
            E = D * 100000 + D * 10000 + D * 1000 + D * 100 + D * 10 + D;
            if (E % A == 0)
            {
                F = E / A;     //F=ABCAB
                //万位数和十位数相等值为A
                if (F / 10000 == A && (F % 100 / 10 == A)) 
                {
                    //千位数和个位数相等(B)
                    if (F % 10 == F / 1000 % 10)
                    {
                        //输出结果
                        printf("%d * %d = %d\n", F, A, E);
                    }
                }
            }
        }
    }
    return 0;
}


3.4狱吏问题

  问题描述:狱吏问题;某国王对囚犯进行大赦,让一狱吏n次通过一排锁着的n间牢房,每通过一次按所定规则转动n间牢房中的某些门锁,每转动一次原来锁着的被打开,原来打开的被 锁上通过n次后,门锁开着的,牢房中的犯人被放出,否则,犯人不得释放。
       转动门锁的规则是这样的,第一次通过牢房,从第一间开始转动每一把锁,即把全部锁打开;第二次通过牢房时,从第二间开始,每隔一间转动一次;……;第k次通过牢房,第k间开始转动,每隔k-1 间转动一次;问经过n次后,那些牢房的锁依然是开着的。

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int n = 0;
    int i = 0;
    int j = 0;
    int* p = NULL;

    scanf("%d", &n);
    //开辟存储空间
    p = (int *)calloc(n + 1, sizeof(int));     
    for (i = 1; i <= n; i++)
    {
    //将锁的状态初始化为关闭,1表示锁上,0表示打开
        p[i] = 1;
    }
    //i表示通过牢房的次数,j表示要转动的锁的编号
    for (i = 1; i <= n; i++)
    {
        for (j = i; j <= n; j += i)
        {
            //切换锁的状态
            p[j] = 1 - p[j];
        }
    }

    for (i = 1; i <= n; i++)
    {
        if (p[i] == 0)
        {
            printf("%d is free \n", i);
        }
    }

    free(p);
    return 0;
}


 


总结

蛮力法是一种简单但有效的算法设计方法。它通过穷举所有可能的解来找到符合条件的最优解。以下是对蛮力法的总结:

优点:

  1. 直观简单:蛮力法的思想直观明了,容易理解和实现。
  2. 适用性广泛:蛮力法可以解决各种问题,特别适用于小规模问题或作为其他算法的基础。
  3. 可靠性高:由于穷举了所有可能的解,蛮力法能够找到确切的最优解。

缺点:

  1. 效率低:蛮力法需要枚举所有可能的解,当问题规模较大时,时间复杂度通常很高,运行效率较低。
  2. 需要大量计算资源:由于需要遍历所有解空间,蛮力法可能需要大量的计算资源,尤其是在搜索空间很大的情况下。
  3. 不适用于复杂问题:对于复杂的问题,蛮力法的穷举方法可能不可行,因为解空间太大,无法在合理的时间内得到结果。

总结: 蛮力法是一种简单直接的算法设计方法,适用于小规模问题或作为其他算法的基础。它的优点是直观简单、适用性广泛和可靠性高,但缺点是效率低、需要大量计算资源,并且不适用于复杂问题。在实际应用中,我们需要根据问题的特点和需求,权衡蛮力法的优缺点,选择合适的算法设计方法。

  • 28
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值