前言
蛮力法感觉是在用最笨的方法解决问题,但是对一些问题不乏适用性。对于算法中的多种问题的求解我们大多时候还是会用其他算法技术,这里只是大概看看有哪些算法问题。
1.设计思想
蛮力法又叫枚举法或穷举法,基本技术是遍历,即按照某种策略依次处理待求解问题的所有元素,从而找出所有的元素。
2.查找问题中的蛮力法
2.1顺序查找
【问题】在查找集合中依次查找值为k的元素,若查找成功,则给出该元素在查找集合中的位置;若查找失败,则给出失败的信息。
【算法实现1】
int SeqSearch(int r[],int n,int k)
{
int i=n-1;
while(i>=0&&r[i]!=k)
i--;
return i;
}
【算法分析1】
基本语句:i>0和r[i]!=k
执行次数:2×1/n×(1+n)×n/2=n+1=O(n)
【算法实现2】设置一个哨兵
int SeqSearch(int r[],int n,int k)
{
r[0]=k; //设置哨兵
int i=n;
while(r[i]!=k)i--;
return i;
}
【算法分析2】
基本语句:r[i]!=k
执行次数:(n+1)/2=O(n)
2.2串匹配问题
【问题描述】给定两个字符串S和T,在主串S中查找子串T的过程称为串匹配,T称为模式。设主串S=“abcabcacb”,模式T=“abcac”
【算法实现】BF算法,即暴力算法
#include<iostream>
using namespace std;
int BF(char S[],char T[])
{
int index=0;
int n=0,m=0;
while((S[n]!='\0') && (T[m]!='\0'))
{
if(S[n]==T[m])
{
n++;m++;
}
else
{
index++;n=index;m=0;
}
}
if(T[m]=='\0') return n+1;
else return 0;
}
int main()
{
char s[30];
gets(s);
char t[20];
gets(t);
cout<<BF(s,t);
}
【算法分析】假设在第i个位置匹配成功了,那么在前i-1趟中共比较了(i-1)×m次,第i趟比较了m次,所以总的比较了i×m次,时间复杂性是O(n×m)
【代码优化】KMP算法
首先计算模式串T的next数组,求解过程如下:
void GetNext(char T[],int next[])
{
int i,j,len;
next[0]=-1;
for(i=1;T[i]!='\0';i++)
{
for(len=i-1;len>=1;len--)//相等子串的最大长度是j-1
{
for(j=0;j<len;j++)
{
if(T[j]!=T[i-len+j])break;//依次比较T[0]~T[len-1]和T[i-len]~T[i-1]
}
if(j==len)
{
next[i]=len;
break;
}
}
if(len<1)next[i]=0;//没有相等的子串
}
}
KMP算法:
int KMP(char S[],char T[])
{
int i=0,j=0;
int next[10]={-2};
GetNext(T,next);
while(S[i]!='\0'&& T[j]!='\0')
{
if(S[i]==T[j])
{
i++;
j++;
}
else
{
j=next[j];
if(j==-1)
{
i++;
j++;
}
}
}
if(T[j]=='\0')
{
return (i-strlen(T)+1);
}
else return 0;
}
主函数:
int main()
{
cout<<"S:";
char S[10];
gets(S);
cout<<"T:";
char T[10];
gets(T);
cout<<KMP(S,T);
}
【算法分析】在算出next数组后,KMP算法的时间复杂度是O(n)即把字符串T扫描了一下。而计算next值的时间代价最坏是O()
3.排序问题中的蛮力法
3.1选择排序
【问题描述】初始序列:49 27 65 76 38 13,按升序排序
【算法实现】
#include<iostream>
using namespace std;
void SelectSort(int a[],int n)
{
int i,j,index,temp;
for(i=0;i<n-1;i++)
{
index=i;
for(j=i+1;j<n;j++)
{
if(a[j]<a[index])index=j;
}
if(index!=i)
{
temp=a[i];a[i]=a[index];a[index]=temp;//不是a[i]=a[j]
}
}
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
}
int main()
{
int a[6]={49,27,65,76,38,13};
SelectSort(a,6);
return 0;
}
【算法分析】时间复杂性是O()
3.2起泡排序
【问题描述】起泡排序的基本实现是两两比较,如果反序就交换,直到没有反序的记录为止
就像冒泡一样,起泡越来越大。
【算法实现】
#include<iostream>
using namespace std;
void Bubblesort(int a[],int n)
{
int bound=0;
int exchange=n-1;//第一趟起泡排序的区间[0,n-1]
int i,temp;
while(exchange!=0)
{
bound=exchange;
exchange=0;
for(i=0;i<bound;i++)//一趟起泡排序的区间是[0,bound]
{
if(a[i]>a[i+1])
{
temp=a[i];a[i]=a[i+1];a[i+1]=temp;
exchange=i; //计录每一次交换的位置
}
}
}
for(i=0;i<n;i++)
cout<<a[i]<<" ";
}
int main()
{
int a[8]={50,13,55,97,27,38,49,65};
Bubblesort(a,8);
}
【算法分析】基本语句是a[i]>a[i+1],时间复杂度是O()
4.组合问题中蛮力法
4.1 0/1背包问题
十分经典的题目,后面用其他算法技术解决。
【问题解决】
对集合中的每个子集计算价值,取得到最大价值的那个子集。
【算法分析】对于有N个元素的集合,其子集数量是,复杂性下界是Ω()。
4.2 任务分配问题
也是一道很经典的题目
【问题描述】假设有n个任务需要分配给n个人执行,每个任务只能分配给一个人,每个人只执行一个任务,且第i个人执行第j个任务的成本是(1<=i,j<=n),任务分配问题要求找出总成本最小的分配方案。
【问题解决】对集合的全排列进行考察
【算法分析】全排列数量是n!,所以时间下界是Ω(n!)
5.图问题中的蛮力法
5.1哈密顿回路问题
【问题描述】哈密顿回路问题要求从一个城市出发,经过每个城市恰好一次,然后回到出发城市。
【问题解决】对结合{1,2,3,4,5}进行全排列,依序对排列进行判断是否是回路,是的话结束,不是的继续考察下一个排列。
【算法分析】最坏的情况下要考察顶点集合的所有全排列
5.2TSP问题
【问题描述】TSP问题是指旅行家要旅行N个城市然后回到出发城市,要求各个城市经历仅经历一次,并要求所走的的路程最短。
【问题解决】找出所有可能的旅游路线,即依次考察图中所有顶点的全排列,从中选取路径长度最短的哈密顿回路
【算法分析】必须依次考察顶点集合的所有全排列,从中找出路径最短的简单回路,时间下界是
Ω(n!)
6.几何问题中的蛮力法
【问题描述】要求在一个包含n个点的集合中找出距离最近的两个点。
【问题解决】分别计算每一对点之间的距离,然后找出距离最小的那一对。
【算法分析】时间复杂度是O()