【算法】蛮力法

前言

概念

蛮力法(brute force):直接基于问题的描述和所涉及的概念定义的进行算法设计,简单而直接。

蛮力法应用特点

  1. 蛮力法所能解决的问题跨越的领域非常广泛。
  2. 对于一些重要的问题,运用蛮力策略可以设计出具备一定实用价值的算法,并且不用限制实例的规模。
  3. 当要解决的问题实例不多并且可以接受蛮力法的运算速度时,蛮力法的设计代价通常较为低廉。
  4. 蛮力算法可以作为衡量其它算法的准绳,服务于研究或教学。

枚举法

算法框架

  1. 依据问题,设定枚举范围;
  2. 找出约束条件,建立计算模型;
  3. 利用计算模型在枚举范围内搜索可能的解。

例题1

输入n个数字(在0与9之间),然后统计出这组数中相邻两个数字组成的链环数字对出现的次数。如:n=20,输入为0 1 5 9 8 7 2 2 2 3 2 7 8 7 8 7 9 6 5 9,则输出为(7,8)=2,(8,7)=3,(7,2)=1,(2,7)=1,(2,2)=2,(2,3)=1,(3,2)=1。

问题分析

可以利用一个二维数组a[10][10]a[10][10]存储出现的数字队。
首先,将二维数组初始化a[i][j]=0(0i<10,j<10)a[i][j] = 0 \quad(0\leq i<10,\leq j<10)
然后,每输入一个数字对,则把对应下标的数组元素加1,如数据输入的序列为xx,则a[xk][xk+1]=a[xk][xk+1]+1a[x_k][x_{k+1}] = a[x_k][x_{k+1}]+1
如题目中的例子可以构建出如下的二维数组:
【算法】蛮力法

计算模型

输入序列:xx
初始化:a[i][j]=0(0i<10,j<10)a[i][j] = 0 \quad(0\leq i<10,\leq j<10)
a[xk][xk+1]=a[xk][xk+1]+10k<na[x_k][x_{k+1}] = a[x_k][x_{k+1}] +1 \quad 0 \leq k <n
最后,统计完毕后,输出a

算法设计与描述

【算法】蛮力法

算法分析

【算法】蛮力法

例题2

解数字谜,如下
【算法】蛮力法

问题分析

一共可以采用三种方式

  1. 枚举测试:五位数的范围为30000-99999。时间复杂度为99999-30000 + 1 = 70000次
  2. 采用构造式的枚举法:A取值从3-9,B-C取值0-9。时间复杂度为71010 = 700
  3. 构造式的枚举法——除法:D的值从1-9,而A的取值仍然从3-9。两重循环,时间复杂度为7*9=63。

计算模型

主要针对第三种进行分析
Ai[3,9],Dj[1,9]A_i\in [3,9],D_j \in [1,9]
{D=Dj105++DjD  mod  Ai==0DAiSi=D/AiB1=Si  mod  10A1=(Si/10)  mod  10C=(Si/102)  mod  10B2=(Si/103)  mod  10A2=(Si/104)  mod  10 \left\{ \begin{array}{lr} D = D_j*10^5 +\dots +D_j & \\ D \;mod\; A_i == 0&上一步算得的D可以被A_i整除\\ S_i = D/A_i & \\ B_1 = S_i\; mod\; 10& \\ A_1 = (S_i/10) \; mod \;10\\ C = (S_i/10^2) \; mod \;10\\ B_2 = (S_i/10^3)\; mod\; 10& \\ A_2 = (S_i/10^4) \; mod \;10\\ \end{array} \right.
判断DD是否可以被AiA_i整除,A1A_1A2A_2是否相等,B1B_1B2B_2是否相等,上述条件均成立,则找到一个解。

算法设计与描述

输出:五位数ABCAB,六位数DDDDDD
【算法】蛮力法

例题3

输出玫瑰矩阵,其为n*n的方阵,特征如下所示对应下标的数组元素加1
【算法】蛮力法

问题分析

设矩阵为a[n,n]a[n,n]可以采用两种思路

  1. ii代表圈数(从0开始),j代表圈内下标变化量:
    {a[j,i]kkk+1jj+1a[ni1,j]kkk+1jj+1a[j,ni1]kkk+1jj1a[i,j]kkk+1jj1 \left\{ \begin{array}{lr} a[j,i]\gets k & k\gets k+1& j\gets j+1&左侧\\ a[n-i-1,j]\gets k & k\gets k+1& j\gets j+1&底侧\\ a[j,n-i-1]\gets k & k\gets k+1& j\gets j-1&右侧\\ a[i,j]\gets k & k\gets k+1& j\gets j-1&顶侧\\ \end{array} \right.
    若n为奇数,还需要最后处理,令a[(n1)/2,(n1)/2]=n2a[(n-1)/2,(n-1)/2] = n^2
  2. 可以看出每半圈元素值增长规律变换一次
    设增量t=1t = 1,每半圈变换一次ttt \gets -t
    设矩阵边长为i,每半圈的元素就是2i12*i-1个,hchc为半圈内计数变量,0hc<2i10\leq hc<2*i-1,前1/4圈是0hc<i0\leq hc<i,后1/4圈是ihc<2i1i\leq hc<2*i-1
    其中iinn开始变换,每过半圈 i=i1i = i-1

计算模型

【算法】蛮力法

算法设计与描述

【算法】蛮力法

算法分析

【算法】蛮力法

穷举查找

有一些求最优解的问题经过抽象,可以转换为组合优化问题,使用蛮力法来求解是一种简单的方法,称之为穷举查找(exhaustive search)。

例题4

旅行商问题(traveling salesman problem,TSP) 有一个旅行商由某市出发,经过所有给定的n个城市后,再回到出发的城市。除了出发的城市外,其它城市只经过一回。这样的回路可能有多个,求其中路径成本最小的回路。

问题分析

给出一个问题实例,如下
【算法】蛮力法
可以通过遍历a - d的全排列来实现问题求解。

计算模型

  1. 存储 利用图G(V,E)。边以临界矩阵形式存储,如下
    【算法】蛮力法
  2. 计算 列出所有路径
    a - b - c - d - a
    a - b - d - c - a
    a - c - b - d - a
    a - c - d - b - a
    a - d - b - c - a
    a - d - c - b - a
  3. 计算路径代价
    【算法】蛮力法

算法设计与描述

【算法】蛮力法

算法分析

T(n)=i=0n1T(i+1)+CT(n)=\sum_{i=0}^{n-1}T(i+1)+C

例题5

背包问题。给定nn个重量为w1,w2,wnw_1, w_2,…w_n,价值为v1,v2,vnv_1, v_2,…v_n的物品和一个承重为WW的背包,求将这些物品中的某些装入背包中,在不超出重量WW的情况下,价值最高的装法。

问题分析

【算法】蛮力法

计算模型

【算法】蛮力法

算法设计与描述

【算法】蛮力法

图的搜索

图的两个重要的遍历算法:深度优先查找(depth-first search, DFS)和广度优先查找(breadth-frist search, BFS),是穷举查找的重要应用之一。

深度优先查找

【算法】蛮力法

广度优先查找

【算法】蛮力法

例题6

迷宫问题。如图所示,图中方格内标为0的为通路,标为1墙。(0,0)为迷宫入口,(7,7)为迷宫出口,请查出由(0,0)到(7,7)的路径。
【算法】蛮力法

问题分析

  1. 存储
  2. 移动

计算模型

  1. 存储
    采用二维矩阵maze[n][n],进行存储
    其中maze[x][y] = 0表示通路,maze[x][y]=1表示墙,maze[x][y]=2表示死路,maze[x][y] = 3表示已经走过。
  2. 行走相对路径
    行走方向:fx[]={-1,1,0,0 },fy[]={0,0, -1,1}
    行走过程:nextx=x+fx[i],nexty=y+fy[i]
    其中,i=0, 1, 2, 3。

算法设计与描述

【算法】蛮力法

算法分析

  1. 迷宫矩阵:maze[n][n]
  2. 依据不同的行走方向,可知T(n,n)=T(n1,n)+T(n+1,n)+T(n,n1)+T(n,n+1)T(n, n)=T(n-1,n)+T(n+1,n)+T(n, n-1)+T(n,n+1)。然而,这公式并不准确,因为墙的布局对算法的影响很大,所以,最坏情况下,所有顶点都测试过,这时,时间复杂度为
    T(n)=O((nn1)4)T(n)=O((n*n-1)*4)
  3. 存储空间中包括递归时的所用的栈,所以,空间复杂度至少为O(2n2)O(2*n^2)