枚举算法及其优化

引言:

总结一下这个简单的算法~

一、什么是枚举算法:

枚举算法很简单,就是将问题的所有可能列举出来,然后通过筛选,找出解,它的时间复杂度通常很大,在一些题目中可能会TLE,因此重要的是如何优化所写的枚举算法。

二、枚举算法优化的思路:

删除重复和不可能出现的情况。重复和不可能出现的情况都列出来,找到其中的规律。

三、经典例题:

我们上一道经典例题:

题目描述:有一个n×m 方格的棋盘,求其方格包含多少正方形、长方形(不包含正方形)。

输入格式:一行,两个正整数n,mn≤5000,m≤5000)。

输出格式:一行,两个正整数,分别表示方格包含多少正方形、长方形(不包含正方形)。

样例:输入——2 3 输出——8 10

我的最终代码:

第一次思路:

纯暴力枚举,确定一个矩形需要四个指针,四个指针可以确定长和宽长度,因此分别设为row(列底),pointr(列顶),col(行首),pointc(行尾),我用word文档以展示:

枚举算法及其优化_第1张图片

长就是pointc - col + 1,宽就是pointr - row + 1。

我们设a = pointr - row,b = pointc - col,注意,a和b并不是长和宽,而是长宽-1得到的,因此当长或宽为1时,代表的a和b是0.

只要判断他们相等是一个正方形。

在判断之前,我们通过找规律可以总结出一个n*m矩形的所有子矩形的公式:

oblong = ((1.0/2)*m*m+(1.0/2)*m)*((1.0/2)*n*n+(1.0/2)*n);

因此,只要将总子矩形个数减去正方形个数,就是除了正方形之外的长方形个数。

第一次暴力的代码,用了四个for,直接TLE了不少样例,只AC了3个。

第二次思路:

通过找规律,col值不变而pointc向右移动时,正方形只能出现一次,也就是一个col值只能有一个正方形,因此在第四个for,if判断找到正方形后,用break从col进入到col+1,代码只是多了一个break:

发现多AC了一个,但是还是有很多TLE了。

第三次思路:

通过找规律,我发现对于一个1*m的矩阵,1*1正方形有m个,那么在暴力枚举找这个1*1正方形时,就会重复枚举1*1正方形m次,能不能只需要枚举1次,就可以一次性找到m个1*1正方形?同理,对于,2*m矩阵,2*2正方形则有m-1个,能不能只需要枚举一次,就可以找到m-1个2*2正方形?

通过一一列举这些已经重复的情况,我们发现一个公式,列数m - 正方形长度 + 1 = 正方形个数。进一步化简,正方形个数x = m - a;

那么我们就可以通过列数的值,确定一个n*m长方形(n > m)的正方形个数,n*m长方形的n*n正方形个数x = m - a;a通过双指针pointr与row得到,因此可以将两个for省略,得到两个for的暴力枚举代码:

这时候就已经满足时间限制了,大大减少了时间复杂度,然而我还不是很满足,能不能做到一个for?

第四次思路:

仿照寻找重复性的优化思路,我发现在行的方向上也存在重复性,即一个7*6矩阵,分成7个1*6矩阵,那么这7个1*6矩阵的正方形个数是一样的,都是6个,同理,分成6个2*6矩阵,则2*2正方形个数也是一样的,是5个。那么,7*6就得到了7个1*6矩阵的总1*1正方形个数,6*5就得到了6个2*6矩阵的2*2正方形总个数,能不能通过一次枚举,枚举出一个1*6矩阵的1*1正方形个数,就可以得到7个1*6矩阵1*1正方形总个数?

我们发现只需要将1*6矩阵正方形个数乘以7就可以得到1*1正方形总个数,同理2*6矩阵。因此存在一个未知数times,times乘以1*6矩阵正方形个数就可以得到所有的1*1正方形个数,通过列出所有的重复情况,我们得到times = 行数n - a的结果。我们进行一个循环,让row一直在1位置,pointr从1到行数n,pointr和row的每个组合就是:1*6,2*6,3*6,4*6,5*6,6*6,7*6矩阵,可以分别找出所有的1*1,2*2,3*3,4*4,5*5,6*6正方形,于是就有了最上面第一个代码段的结果,只需要一个for就能找出所有的正方形。

看到这里你也很不容易,祝你学习快乐~喜欢的话欢迎点赞关注哦~

你可能感兴趣的:(算法,算法,c++)