算法分析之蛮力法(暴力法)

目录

1, 蛮力法的概述及定义

1.1,求解问题所要依据的步骤

2,例题演练

2.1百鸡百钱问题

2.2 排序问题

2.2.1 选择排序

2.2.2 冒泡排序

2.3 查找问题


1, 蛮力法的概述及定义

蛮力法——简单说是一种简单直接的算法设计策略,也叫作暴力法,枚举法或者穷举法,蛮力法解决问题常常简单粗暴,常常基于问题的描述和所涉及的概念,定义直接求解,逐一列举并且处理问题所涉及的所有情形,然后得到问题的答案。在求解问题的过程中往往依据循环结构来实现。

1.1,求解问题所要依据的步骤

(1)确定扫描和枚举变量。

(2)确定枚举变量的范围,设置相应的循环。

(3)根据问题的描述确定约束的条件,以便找到合理 的解。

2,例题演练

2.1百鸡百钱问题

为题描述:数学家张丘建提出百鸡百钱问题,今有鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一。百钱买百鸡,问鸡翁,鸡母,鸡雏各几何?

问题分析:设鸡翁,鸡母,鸡雏分别为x,y,z,题意给出一百钱要买百鸡,如果全买公鸡最多买20只,显然x在0—20之间,同理y的取值在0-33之间,所以根据分析,不难用枚举法求出问题的所有符合情况的解。

void HundredFowlsMoney()
{
	int z = 0;
	for (int x= 0; x < 20; x++)//鸡翁的数量变化范围
	{
		for (int y = 0; y < 33; y++)//鸡母的数量变化范围
		{
			z = 100 - x - y;
			if (z % 3 == 0 && 5 * x + 3 * y + z / 3 == 100)//鸡雏z受x,y的制约
			cout << "鸡翁:" << x << endl;
			cout << "鸡母:" << y << endl;
			cout << "鸡雏:" << z << endl;
		}
	}
}

2.2 排序问题

2.2.1 选择排序

基本思想:对有n个元素的序列进行n-1趟排序,第一趟排序对序列进行从头到尾扫描,找到最小的元素与第一个元素交换;第二趟排序从第二个元素起开始扫描,依然找到最小元素和第二个交换,;一般来说,第i趟排序从序列的第i个元素起到序列尾的n-i+1个元素中找到最小元素,然后和第i个元素交换顺序,按照上述方法完成对n个元素的排序。

//选择排序
void SelectSort(int arr[], int n)//对数组里面的n个元素进行排序
{
	int min;
	int temp = 0;
	for (int i = 0; i <= n - 2; i++) {
		min = i;//在此处假设第一个元素最小,记住其下标
		for (int j = i + 1; j < n; j++)
		{
			if (arr[j] < arr[min])
				min = j;//在这里如果找到比当前元素更小的,就记住其下标
		}
		temp = arr[i];//在这里进行交换,把第i个元素和搜索到的最小元素交换,min永远保存
		arr[i] = arr[min];//最小元素的下标
		arr[min] = temp;
	}
}

在这里方便大家理解,我以7个元素数组的例子来模拟一遍选择排序的算法。

初始序列:80,18,72,95,29,45,12

第一趟排序:|80,18,72,95,29,45,12   i=0:min最后的6,交换二者

第二趟排序:12,|18,72,95,29,45,80   i=1:min最后得1,不交换

第三趟排序:12,18,|72,95,29,45,80  i=2:min最后得4,交换二者

第四趟排序:12,18,29, |95,72,45,80  i=3:min最后的5,交换二者

第五趟排序:12,18,29,45,|72,95,80   i=4:min最后得4,不交换

第六趟排序:12,18,29,45,72,|95,80  i=5,min最后得6,交换二者

最后一趟排序:12,18,29,45,72,80,|95   排序结束

以上标红色的数字是每趟需要和第i个元素交换的数字,在排序过程中,竖线左侧是已经排好的元素,每次从竖线右侧第一个元素开始扫描,直到扫描完最后一个元素,找到本轮的最小元素,将最小元素和第i和元素交换位置即可,经过n-1趟完成排序,n代表输入元素规模。

2.2.2 冒泡排序

冒泡排序基本思想:对具有n个元素的序列也进行n-1趟排序。第一趟排序对序列进行从头到尾进行相邻元素的比较,如果是逆序(即大在前小在后),则进行相邻元素之间的交换,这样经过一趟排序后,最大元素沉到了数组的第n个位置,第二趟排序对数组进行从头到n-1个元素进行相邻元素之间的比较,如果逆序就交换,这样经过第二趟排序,次大元素就沉到数组的倒数第二个位置,第i趟排序从数组的头到数组的第n-i+1个元素进行相邻之间的比较,,依次做同样的操作,一趟排序后,第i大的元素就落在了第n-i+1的位置上,经过n-1趟排序,即可完成对数组的排序操作。

//冒泡排序,递增排序
void BubbleSort(int arr[], int n)
{
	int temp = 0;
	for (int i = 0; i < n - 1; i++) {
		for (int j = 0; j <= n - 2 - i; j++)
		{
			if (arr[j + 1] < arr[j])//每一次都比较相邻的两个元素
			{
				temp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = temp;
			}
		}
	}
}
//冒泡算法改进算法
加入我们输入的序列本身就有序,那么经过一次扫描后,发现没有进行一次元素交换,说明序列是有序的,就直接跳出循环,所以在这里我们设置一个flag标志位
void BubbleSort(int arr[], int n)
{
	int temp = 0;
	int flag = true;//在这里设置标志位
	for (int i = 0; i < n - 1&&flag; i++) {//判断是否进行了交换,如果没交换说明序列有                                
		for (int j = 0; j <= n - 2 - i; j++)//序,直接就退出循环
		{
			if (arr[j + 1] < arr[j])
			{
				temp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = temp;
				flag = false;
			}
		}
	}
}

在这里写出对7个元素的数组进行排序的模拟过程,以方便大家理解。

初始序列:80,18,72,95,29,45,12

第一趟排序:18,72,80,29,45,12,|95  i=0;最大值95就位

第二趟排序:18,72,29,45,12,|80,95  i=1:最大值80就位

第三趟排序:18,29,45,12,|72,80,95  i=2:最大值72就位

第四趟排序:18,29,12,|45,72,80,95  i=3:最大值45就位

第五趟排序:18,12,|29,45,72,80,95  i=4:最大值29就位

第六躺排序:12,|18,29,45,72,80,95  i=5:最大值18就位,n-1趟排序结束。

红色标明的数字是每趟选出的最大值放到的位置。在算法执行过程中,竖线右侧是已经排好序的元素,扫描时从左端开始,每次比较当前与其右侧的元素,如果逆序就交换,经过n-1趟完成排序,n代表输入元素规模。

2.3 查找问题

顺序查找算法:字符串匹配,在这里待查找的字符串称为文本,与其进行部分匹配的字符串称为模式,字符串匹配问题的蛮力法求解是将模式对准文本的开始位置,从左到右逐一查找对应的字符,如果相同,就查找下一个字符;如果不同,则将模式的起始位置重新设置为开始的位置(相当于对应的匹配位置又重新开始),如果成功找到匹配位置,则返回最左端字符在文本中的位置。如果匹配的位置距离文本最后 字符长度小于模式串的长度,则返回匹配失败。例如第一个文本长度为n,模式串的长度为m,则在文本中可能匹配成功的位置在0至n-m,应为在n-m的右侧字符串距离文本最后一个字符的长度已经不足m,匹配一定不成功。所以算法实现如下:

//W_arr[]表示文本串,M_arr[]表示模式串,w_num, m_num分别表示文本串和模式串的长度
int BruteForceIndex(int W_arr[], int M_arr[], int w_num, int m_num)
{
	for (int i=0; i < w_num - m_num; i++)
	{
		int j = 0;
		while (j < m_num&&W_arr[i+j] == M_arr[j])//判断模式串是否匹配成功
		{
			j++;
			if (j == m_num)
				return i;//如果匹配成功,返回模式串在文本中的第一个字符下标
		}
	}
}
p a t c h   n o t   a p p l i e d
a p p                            
  a p p                          
    a p p                        
      a p p                      
        a p p                    
          a p p                  
            a p p                
              a p p              
                a p p            
                  a p p          
                    a p p        

以上为字符串app的模拟执行过程,加粗的字符表示每次匹配匹配不成功的字符,直到最后一次匹配完成,返回app在文本串中匹配成功第一个字符的位置。

当然还有很多蛮力法的例子,比如几何问题,凸包问题等等,在这里只是简单论述一下蛮力法求解问题的方法,以便我们拿到一个问题后,在不知道什么方法最合适的情况下,尽快用暴力求解法解决问题,本篇博文还会持续更新,欢迎大家指出不足,谢谢大家。

你可能感兴趣的:(acm基础算法,算法设计与分析,考研算法题目)