一些算法及题目总结

 

 

1. 广告排名区间 


问题背景 
shifen广告消费预估系统可以估计出一段时间内一个特定的广告在检索结果中排在各个位置的机率。比如系统对某广告的输出如下: 
p1 = 0.03, p2 = 0.08, p3 = 0.04 …… 
这说明该广告展现在第1位的概率是 3%,展现在第2位的概率是 8%,展现在第3位的概率是 4%…… 

问题是:如何给出一个排名估计区间[i, j],使得广告出现在该区间中的概率大于或等于一个预设值p,同时这个区间所包含的元素尽可能的少。也可用数学语言来描述:给定数p和数列 p1, p2, … , pn,求 i和 j (1 <= i <= j <= n),在满足pi + pi+1 + … + pj >= p的前提下让j-i 最小。 
一般来说,pi只需保留6位小数就足够了。这样,若令ai=106pi,a=106p,则a和所有的ai均为[0,106]之间的整数。这样就避免了对实数的处理。 
输入格式 
第一行包含一个整数n (1 <= n <= 100,000)。 
以下n行每行包含一个[0,106]内的整数,依次为a1,a2,…,an。这n个整数之和保证不超过106。 
最后一行包含一个[0,106]内的整数a。保证所有ai之和不小于a。 
输出格式 
输出仅一行,包含一个整数,即j – i的最小值。 
样例输入 





10 


18 
样例输出 

 

 

 

 

 

 2, 堆排序

堆排序很好用,可以排序出前几个最大,最小值。堆排序中最重要的一步是堆调整。建堆的过程,实际上是对0~n/2的节点进行调整的过程。而排序的过程,事实上就是取堆顶元素然后堆调整的过程。示例代码如下

 

3, 约瑟夫问题

 

N只猴子要选大王,选举办法如下:所有猴子按1-N编号围坐一圈,从1号开始按顺序1,2,,,m报数,凡报到m的猴子退出到圈外,如此循环报数,直到圈内只剩下一只猴子时,这只猴子就是大王。N和M由输入文件提供,要求在输出文件中打印出最后剩下的猴子的编号。数据规模

 

 

 

 

 

4,最长数字子序列问题。

给定一个字符串例如:sfjajf1234123jhjsdlfjakfsdlj123123123jflajsfdkas2342342。给出最长的数字子序列,并输出该子序列的长度。当然可以扫描一遍,记录所有的数字序列的起始地址,长度,比较找出最长的。但这显然复杂了。可以在o(n)时间内搞定。也就是说仅需遍历一遍。

 

 

5,亚特兰数~

关于一下的几种问题

 

1.括号化问题。

  矩阵链乘: P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?(h(n)种)

2.出栈次序问题

  一个栈(无穷大)的进栈序列为1,2,3,..n,有多少个不同的出栈序列?

  类似:

  (1)有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票,剧院无其它钞票,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票找零?(将持5元者到达视作将5元入栈,持10元者到达视作使栈中某5元出栈)

  (2)在圆上选择2n个点,将这些点成对连接起来,使得所得到的n条线段不相交的方法数。

3.将多边行划分为三角形问题

  将一个凸多边形区域分成三角形区域的方法数?

  类似:一位大城市的律师在她住所以北n个街区和以东n个街区处工作。每天她走2n个街区去上班。如果她

  从不穿越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路?

  类似:在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?

4.给顶节点组成二叉树的问题。

  给定N个节点,能构成多少种形状不同的二叉树?

  (一定是二叉树!

  先去一个点作为顶点,然后左边依次可以取0至N-1个相对应的,右边是N-1到0个,两两配对相乘,就是h(0)*h(n-1) + h(2)*h(n-2) + ... + h(n-1)h(0)=h(n))

  (能构成h(N)个)

 

 


h(n)=C(2n,n)/(n + 1) (n=1,2,3,...)

关于16个人买烧饼的题目,G(16)=h(8)=c(16,8)/9=1430

6,  Fibonacci分解

定理 任意自然数n的Fibonacci分解是唯一的。(F1=1,F2=2)

    设不大于n的最大的fibonacci数为Fb

    Fibonacci分解为:F(n)=Fb+F(n-Fb);

Fibonacci分解是唯一的。

同时附跳棋问题解决方法。跳棋问题:一系列相当长的个子,某些个子里面放了棋子,如果格子里面有棋子,就可以拿走其中的一颗,同时在这个格子的左边两个格子里面放一颗。如果连续两个格子里面都有棋子,可以分别从两个格子中各拿走一颗,之后再他们右边的格子里面放入一颗。

为什么用fabonacci分解?因为以上题目中的两个操作是可逆的。对于三个连续格子,每个格子放1,可以看做后一个是前两个之和。只用给这些格子加上fabonacci的权重就可以了。然后用格子中的棋子乘以格子的权重之和为n,分解n。得到唯一的一组解。对应的格子中放1就是解。解是唯一的。

    至于实际的编程,还要考虑更多的问题。

 

7,序关系计数问题

 

用关系运算符"<"和“=”来表示几个字母的排列。如果是三个数将由13种不同的排列。由于A=B和B=A是一样的。

 

那么首先想到的是递归的方法。

 

不妨设 总共有N个字母。对于N的情况,只用求出当前连接符为<和当前连接符为=的两种情况。=的情况下,我们要求,=号前面的字符ascii小于等号后面的字符。

 

这样的话。对于N个字母的情况。F(N,E,1)=F(N-1,E-a,1)+F(N-1,E-a,2)

对于上述递归式解释。E代表字母集合,a代表该次递归用掉的字母,最后的一个参数代表字母表搜索开始位置。1代表从字母表第一个开始。当关系为<时,可以从字母表第一个开始,搜索未被用过的字母。当关系为=时,只能从当前字母的下面一个开始。

< ;p> 

 

该算法计算很慢。原因是计算了太多重复的子结构

如果当前关系为<时,不管当前选用了什么字符。如果还剩k个的话,这k个字符组成的关系的数字一样的。例如当前选择了a,或者选择了b,在当前关系为<的时候不影响下一步的关系数。然而,在这里计算了太多。

 

事实上,改进到这里,这个算法还有改进的余地。换一个角度来思考。

当前只有一个字符的时候F(1)=1;f(2)=3;这里的f跟上面改进后的一样。

想想一下有3个字符的时候的情况。一个字符相等的情况(其实就是都不等),前两个字符相等的情况,,三个字符相等的情况之和3*f(2)+3*1+1=13。

 

 

那么可以这么来思考,F(n)=C(N,1)*F(n-1)+C(n,2)*F(n-2)。。。+C(n,n)*F(0),令F(0)=1

那么根据上述算法

F(1)=C(1,1)*F(0);

F(2)=C(2,1)*F(1)+C(2,2)*F(0)=3

F(3)=。。。

从而算出F(n)

 

 

 

实际运行一下,时间差距非常之大,尤其在n>10的时候尤为明显。未优化的代码运行速度很慢,所以没有必要设置成double(8字节),int(4字节)足以。改进之后的,可以计算到double的情况。

 

8,用二分查找在无序数组中查找第k大的数字

 

 

 

 

 

 

 

查找的方法:随机找一个数字,然后将小于它的放在它的左边,大于它的放在它的右边。

 

 操作完之后,它在第i个位置,如果i=k,则找到了,否则如果i>k,则在1~i的范围内找第k大,否则,在i+1~n的范围内找k-i-1个数

算法复杂度为O(n)

 

 

 

 

9, 关于枚举01串的一种写法

 

10 最长公共子序列

这个是动态规划的基础题目。动态规划就是递推和重复子结构。

确定了递推关系后。找到一个能极大地减少重复运算的子结构至关重要。选的好了,时间效率会很好。

 

这个问题,不妨设第一个串为a,长度为n,第二个串为b,长度m。那么最长的子序列长度为f(n,m)

当a[n]=a[m]时

f(n,m)=1+f(n-1,m-1)

否则f(n,m)=max(f(n-1),f(m-1))

同时建立一个存储计算过的f(x,y)的矩阵,如果计算过了就直接使用

 

 

程序如下所示

 

 

 

 

11 赛程安排,要求,每人每天只能比赛一次,有2^m个选手,给出一种安排方式,让所有的选手在2^m-1天内,每两个都能够至少比赛一次。

这个题目很有规律。给出问题规模m,2^m个选手,2^m天。那么不妨做出他们的天/人矩阵。当只有一个人的时候,m=0,则只能是1,当问题规模为m+1时,可以将该矩阵分解为4个矩阵。

g(m+1)= |A B| B中的元素等于A中相应位置的元素+2^m,C与B一致,D=A,那么就可以使用递归的方法了。

       |C D|

 

12,计算子n维体的阶级和自己做个记号。这道题的思维过程和方式很值得学习。实际上,我们从小接受的数学训练也不过如此。只是,随着我们的成长,纯数学的东西做的少了,变得愚钝了罢了

 

n维体定义为P((S1,T1),(s2,T2),(s3,T3))

n维体的阶积为(T1-S1)*(T2-S2)...

若T>T1,S<S1,则说新的n维体为上一个的子n维体。T,和S的取值为1,2,3,。。。,n

 

题目要求:求给定n维体的所有子n维体的阶积之和

 

这个题从表面上kan很复杂,对于一维来说,总共有(T-S+1-1)+(T-S+1-2)+。。。+(T-S+1-(T-S))种取法,不妨设T-S=A

则,则共有A*(A+1)/2种取法,在n维空间下的取法将会很大,就t大老师的书上所讲的是O(m^(2^n)),m表示Ai的一般规模。

 

实际上可以进行降维处理不妨设一维下的阶积为F(A1),那么2维下的实际上是F(A2)*F(A1),n维依次。。。

而一维下的阶积为F(A)=1/6*a(a+1)(a+2)

 

在n维情况下就很容易算出来了。问题规模变成了O(n)

提示:遇到问题不要先一味的想最为基本的算法,尤其是基本的方法问题规模很大的时候。不妨罗列试探一下,找到问题的规律,可能有更好的解。

13,求最多因子数

给定一个范围0<n<=M<=1亿,M-N<1百万,求n~m之间拥有最多因子的数

 

首先,可以回顾一下,如何对一个数做质因子分解。很简单,从2开始,如果包含该因子,输出该因子,并且原数字除以该因子。代码如下

如何计算一个数的因子:

给定0~n的范围,在这个范围内,用两重循环

对包含i,j的因子数+2

例如这么来做

for(int i=1;i<floor(sqrt(n));i++)

    for(int j=i+1;j<n/j;j++)

         f[i*j]+=2;

 

但是对于这道题,数字的取值范围很大。不可能开一个一亿的数组,或者一百万的数组

但是可以采用化整为零的方法。将这些数字分成3w一组(T大老师的书),然后来做

代码如下

14,已知a和n,计算a^n

当然可以把a自乘n次。但也有简便的算法。

例如

a=2,n=100=2^6+2^5+2^2。事实上,我们只用作6+3次乘法就可以算出结果,其中的6次是计算到a^(2^6)所用的乘法次数。3次是每一项乘到结果用的次数

 

对此,做一简单实现,普通乘法

同时,由于a^n通常会涉及到大数的运算。做了大数高精度乘法的实现

测试例子

 

2

10

1024

 

 

 

 

2 100

1267650600228229401496703205376

 

 

一百次方的几乎是立刻得到结果

 

15, 奶牛网球赛

 

N个奶牛,每个可以赢自己排名后的,也可以赢自己排名前k个的。问,最大的冷门可能是哪个?

 

方法:实际上,加入第m个奶牛可以赢,那么排名前面的也可以赢。假设可以赢为1,不可能为0.则N个奶牛可以组成一个1,0的序列。一边为0,一边为1,只用求他们之间的临界点就行。

 

用二分枚举。mid可以么?可以,则区间为mid~end,否则,start~mid-1。这样就可以保证找到最后的可以的那一个。

 

(该题做个记号)

 

 

用二分枚举(记号)

二分枚举的另一例子:

城堡围圈士兵发奖章的问题。如果不围圈,直接贪心算法。每次尽量分给已经用过的奖章类型。但是围圈的话,就需要考虑每个和第一个的人的相同的奖章的数量。这种情况下,动态规划是可以的。但是时间复杂度稍微高一些。如果使用x个奖章可以,则x+1个奖章也可以。所以可以使用二分枚举。来枚举最极限的那个点。这个点实际上就是我们想要求的。实际的思考过程还要复杂一些。(该题目不写程序了,留个记号)

二分枚举的另一个例子:

推销员的旅行。从一个城市到另一个城市,在一个城市待一个小时,作宣传,然后到另一个小时。假如他只能查询每天的12点的某个城市到一个城市的航班。假设每个城市之间都有航班,但仅有一架,不间断往返飞行,飞行时间1小时。该推销员需要打电话来查寻。

 

这个题目的二分搜索比较隐晦。 当有i个城市已经安排的时候,安排第i+1个城市的时候,如果第i个城市指向i+!,则直接添加到最后。如果i+1指向第一个城市,直接添加到第一个位置。如果不属于以上的两种情况。则在其中的某个一定可以加进去。如果2不可以,则2一定指向i+1,由于i+1指向i,所以一定能找到。

       用二分搜索的方法,如果mid元素指向i,则在后半部分一定能够找到,则查找后半部分,前半部分有所有都指向i的可能,但并不是说没有可能插入。只是后半部分插入的可能性更大而已。

代码如下,其中没有实现的函数为查询函数,即航班系统提供的查询函数。

 

二分搜索的另一个例子

 

有n个石头,k个框子。把n个石头按顺序放入k个框子,比如1~3放入1,4~6放入2,要求最大重量的框子的重量最小的放法。

该题目可以用动态规划的方法

设f(i,j)表示i个石头放入j个框子的最佳放法...暂时做个记号

用二分法探测

总石头重量sum,[1,sum]之间采用二分探测。例如mid可以,则在1~mid间探测,否则在mid和sum之间探测,这样的时间代价远小于动态规划

代码如下

 

二参数二分搜索举例

 

有n个题目,至少选择连续的k个,使得选择的题目的分值和难度比最大。

 

设,分值为Ai,难度为Bi,则分值难度比为(Ai+...+Aj)/(Bi+..+Bj)>=p

这样就可以改写成,(Ai-Bi*p)+...+(Aj-Bj*p)>=0,我们只用二分查找这个p就可以了

 

这样的话,时间复杂度(NlogT),当然也可以暴力搜索,时间复杂度可以为(N^2)

代码略

 

 16,错排问题。

例如1,2,3,4,每个数字不在自己的位置上就是错排,求错排数量和错排方案

求数量方案一,F(n)=n!-C(n,1)F(n-1)-C(n,2)F(n-2)-...-C(n,n)F(0)。F(0)=1;F(1)=0;

该方案不能用来求错排方案

方案二:求错排的两种方式

            方式a,n与1,n-1交换,剩下的n-2个元素错排

            方式b,n-1个错排,每个元素和n交换

数量    F(n)=(n-1)(F(n-1)+F(n-2)),F(1)=0,F(2)=1

 

实际操作中还需要一些技巧来实现方案二的方式a, 代码如下

17晚餐。妈妈烧了m个骨头分给n个孩子,每个孩子有需求大于min,小于等于max,骨头必须全部分给孩子,求最多的方案数目

 

根据鸽巢原理,把m个鸽子放到n个笼子里,笼子可以为空的情况下有C(m+n-1,n-1)种放法。则每个减去min后,算出来的结果是没有考虑上限的做法。根据容斥原理,可以计算出集合的并(每个集合为单个孩子max下的种类)

代码如下 

18, 单色三角形问题

一个完全图,每两个点之间的连线不是红色就是黑色,求单色三角形的个数。

方法一,枚举所有的三角形。

方法二,三角形个数为c(n,3),异色三角形的个数:只要两条边异色就可以了。则只用求单点异色边对数,然后,总对数就等於单点异色边对数之和的二分之一,一个点的边数为n-1,红色为x,则黑色为n-1-x

代码略

19, 篮球队员身高问题

 n个篮球队员,平均身高2000mm,身高范围1950~2050mm。求一个排列,使得对于任意一个给定的k,任意k个连续队员的身高之和与k*2000之差的绝对值小于100

 

方法:首先,预处理,所有的减去2000,有负有正,分为两个数组。初始总值为0.如果总值加上一个正值小于50,则加上该正值,否则,加上一个负值。由于条件的限制,每个数值的绝对值一定是小于50的。最终一定能找到这样一个序列,因为所有的队员的平均身高为0(2000)

代码如下

 

20, 排列问题

 

在整数1,2,。。。,n中,有些排列满足下面的性质:该排列中除了最后一个数字以外,每个整数后面都跟有一个同它相差为1的整数。例如:N=4,排列1432满足上述性质。求,如果 任意指定p个位置的值,求最多有几个排列满足如上性质

 

这种排列满足一下两条性质

a,任何一个排列的后k位是若干连续整数的集合

b,如果一个排列的后k位(1<=k<=n)是软干连续整数组成的集合,则这个排列满足题目所述的性质。

 

动态规划的方法即可。设s为起始的数的大小,r为连续的多少数的个数

 

g(s,r)=g(s+1,j-1),若第1个位置为s,即倒数第j个位置为s

   g(s,j-1),若第1个位置为s+r-1,即倒数的第j个位置为s+r-1

   不确定则为上述两个之和

 

代码如下

 

 

21,pku 2018

题目是 读入一列正数,以及一个数F,求一段长度大于等于F且平均值最大的子串范围F<=N<=10^5

 

这个题目我花了一些时间,做了一下,验证了一些数据都是正确的,但是提交的时候却总是错的。

这个问题网上也有多种解法,有一个高人用O(N)方法,但是却没有说明,我按照这个算法提交的居然是超时的错误

代码如下

另外一种算法,是利用下凸折线,这个算法比较好,利用了几何性质

代码如下

这个题目算是先留下个纪念吧,好好地思考一下,到底是哪里错了。原来的错误在于题目要求的输出用1000*ncows/nfields的形式,我直接用一个double的ans*1000,这显然是错误的,一个是整形,一个带小数。但后来修改之后依然不对。

 

看了别人的解法,这个方法是实现的凸曲线比较好的方法

 

 

22. 放水

N层储水地下建筑,第一层最靠近地面,第N层就是最底层。第N层有泄水管道和外面的一个大水池相连。每一层都可以蓄水,但有限制:规定第i层的蓄

 

水池的蓄水上限位Li。初始时,每一层有水wi,如果一层的存水量大于该层的上限,该层所有的水都会流入下一层。自动防水的过程不需要费用。也可

 

以选择手动放水,手动放水每层的费用是Pi,求最小费用使得最下一层的水全部流走。

 

从最顶上一层,即就是第一层开始,放第一层的全部的水,然后计算下面需要手动放水的层,一层一层的放,最后放完。然后从第二层开始,

 

就这样一层一层的算,求最小值。

可以优化的地方,如果从第二次开始,也就是说第二次为最顶上手动的,则当前层的L减去的前面的累积和这一块可以优化。

这道题目还是比较简单的。但是刚才看了《老男孩》内心感慨万千,思绪乱飘,居然还调试了一会~~我还年轻~~Rabbit说我们都还正年轻着呢~这首歌写的很不错~当年看了k歌情人之后就反复的听那首歌~~仿佛歌不是为了电影,电影是为了歌而写的。~~

代码如下

 

 

 

 

23, 数列转换。一列数a1,a2,a3,a4,a5...可以做如下操作

(a1,a2,a3)->(a1+a2,-a2,a2+a3)

给定一个数列的初始状态和一个结束状态,判断是否能够通过上述的操作进行转换得到

 

直观的看,经过这种操作之后,数列的和不变,但事实上这个并不能决定例如(1,2,3),(1,3,2)就不能变化得到

 

我们关注部分和S1=a1,S2=a1+a2,S3=a1+a2+a3,则变化前后位(S1,S2,S3)->(S2,S1,S3)

事实上就是部分和交换位置,变换位置的部分和和前面的部分和交换位置。

 

所以判断能否得到,只用判断经过排序的部分和是不是对应的相等。如果相等则可以,如果不等,则不可以。

整个时间代价就是排序的时间代价,计算部分和在输入的同时完成

需要实现排序算法,O(nlogN),也可以直接使用qsort,或者java.util.Arrays.sort().

题目比较简单,实现也没有难度,代码就不写了

 

24 排数游戏

 

初始时,有一系列的数排成一行1~30000,数字i的位置在i列,游戏有两类指令

合并指令 M i j,将第i列的数字放在第j列的后面

查询指令 C i j, 如果i,j在相同的一列,输出他们之间的间隔,否则输出-1

 

25 最优联通子集

//题目:在座标平面内的整点集中,称距离为1的两点相邻,即相邻关系为上下左右

 

//如果S中存在互不相同的点序列R,Q1,Q2,...,Qk,T。其中任意相邻两项的点相邻,

//则称在整点集S中,存在R,T的一条道路。如果S中任意两点之间都有且只有一条路径,

//则称S为单整点集。现给定S并给S中所有点赋一个权,求单整点集B,B是S的子集,且B的权和,最大

 

 

相当于求树的权的最大子树

代码

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章