双色塔问题,读懂屎山代码

现在有红,绿两种颜色的石头,现在我们需要用这两种石头搭建一个塔,塔需要满足如下三个条件: 

1. 第 1 层应该包含1块石头,第2层应该包含两块,第 i 层需要包含 i 块石头。

2. 同一层的石头应该是同一个颜色(红或绿)。

3. 塔的层数尽可能多。 问在满足上面三个条件的前提下,有多少种不同的建造塔的方案,当塔中任意一个对应位置的石头颜色不同,我们就认为这两个方案不相同。石头可以不用完。

数据范围:红绿颜色石头数量满足  0≤a,b≤2×105  ,   a+b≥1 

给出红石头和绿石头的个数,请输出有多少种叠法

说实话,大家都不喜欢看公式,太难懂,程序员大佬普遍不善表达,我个人也是看了一晚上才大概明白这个题的正确答案是甚么意思,在这里就不贴代码了,只讲一下大体的思路,应该能读的更清晰一些。以及想吐槽一下,希望程序员*********把代码写的清晰易懂一些。

先说一下自己怎么做的:没怎么学过动态规划,考虑的是用递归。定义solution(a,b,i),a和b分别表示目前红绿石头分别还剩下多少,i表示我目前数到了第i层,这个函数return的就是目前叠到第i层的时候,还剩a个红石头和b个绿石头,会有多少种解决方案。定义这个函数的作用就是不停地往下一层去数,直到进入最深层

写这个问题先定义递归的尽头,当两种颜色的石头的数量都小于需要的石头数量i时,达到尽头了,这种情况下返回1。其实这一步就很完美了,但是不符合条件3,也就是说如果我们这么做的话,会产生一些比较矮的塔。那么我在这里修改为返回 1,i-1两个输出。也就是同时返回个数和这种情况下能够达到的最大层数,以进行后续的比较。

而在else的情况下,分为三种情况:只有红宝石够用,只有绿宝石够用和两种宝石都够用。

只有红宝石够用时,问题转化为solution(a-i,b,i+1),即本层只能使用红宝石

只有绿宝石够用时,问题转化为solution(a,b-i,i+1),即本层只能使用绿宝石

两种宝石都够用时,问题转化为solution(a-i,b,i+1)和solution(a,b-i,i+1),但这里不能直接相加,因为要比较深度,两种情况的输出要在比较之后进行处理,再return

而第一层为solution(G,R,1),此处为函数的入口。

其实这么做基本上很完美了,但是运行速度较慢,提交的时候是不合格的。下面分享大佬的答案。

此题动态规划整理:最重要的是定义数组以及状态转移方程。

如何定义数组?这里大佬使用的是array[i][j]的形式,其含义为堆到第i层时,已经用了j个绿宝石。此处怎么想到的我也不太好讲,但是你要是问为什么不考虑红宝石呢,我会说后面会使用限定条件来让红宝石达到够用的目的。

核心思路仍然为通过前一层来推导当前层,假设前一层已经叠好。这个想法依赖于甚么呢?依赖于我第一层的结果是很好得到的,正常情况下:

array[1][0]=1,我第一层不用绿宝石,那么结果为1

array[1][1]=1,我第一层用绿宝石,那么结果为1

那么假设我已有array[i][*]的全部信息,我如何获得array[i+1][*]?很简单,我在i+1层,要么我就用绿宝石,要么我就不用,当然此处会写判定条件,看看宝石够不够用。

所以说,当前层只需要获得前一层的信息即可,这样的话我只需要2行1维数组,一行1维数组在本次循环中为当前行,那么在下一次循环中就可以视为上一行。此处是一个节省空间的技巧

int one = lev % 2; int two = (lev - 1) % 2;

这个塔理想状况下能达到多少层?假设每一层都有石头可以叠,而石头总数又不超过实际宝石的总数,就能写出level的定义了:

while (sum <= R + G) { level++; sum += level; }

下面开始真正的计算,此处开始一个超大循环,为当前进行到的层数的叠加

内层循环为当前层已经使用了的绿宝石数的增加,计算在当前层的当前已使用绿宝石数的情况下,会出现多少种方案,上文已给出推导方式,限定条件的核心思想为已使用的绿宝石与红宝石的数量均够用

最后,循环将推导出最深层的结果,即最深层的组合方式,将最深层的array[][]的那一行进行求和,即为结果。

源码详见:https://codeleading.com/article/2412986569/

难点还是在于怎么定义array数组,此处为只考虑一种宝石的消耗数量,而另一种宝石的消耗后续会用条件来限定,因此可以不再考虑。这种思路可以去参考。状态转移不是特别困难。希望自己能把这个问题以一种不太程序员的方式讲明白。

#算法刷题笔记#
全部评论

相关推荐

头顶尖尖的程序员:我也是面了三四次才放平心态的。准备好自我介绍,不一定要背熟,可以记事本写下来读。全程控制语速,所有问题都先思考几秒,不要急着答,不要打断面试官说话。
点赞 评论 收藏
分享
避坑恶心到我了大家好,今天我想跟大家聊聊我在成都千子成智能科技有限公司(以下简称千子成)的求职经历,希望能给大家一些参考。千子成的母公司是“同创主悦”,主要经营各种产品,比如菜刀、POS机、电话卡等等。听起来是不是有点像地推销售公司?没错,就是那种类型的公司。我当时刚毕业,急需一份临时工作,所以在BOSS上看到了千子成的招聘信息。他们承诺无责底薪5000元,还包住宿,这吸引了我。面试的时候,HR也说了同样的话,感觉挺靠谱的。于是,我满怀期待地等待结果。结果出来后,我通过了面试,第二天就收到了试岗通知。试岗的内容就是地推销售,公司划定一个区域,然后你就得见人就问,问店铺、问路人,一直问到他们有意向为止。如果他们有兴趣,你就得摇同事帮忙推动,促进成交。说说一天的工作安排吧。工作时间是从早上8:30到晚上18:30。早上7点有人叫你起床,收拾后去公司,然后唱歌跳舞(销售公司都这样),7:55早课(类似宣誓),8:05同事间联系销售话术,8:15分享销售技巧,8:30经理训话。9:20左右从公司下市场,公交、地铁、自行车自费。到了市场大概10点左右,开始地推工作。中午吃饭时间大约是12:00,公司附近的路边盖饭面馆店自费AA,吃饭时间大约40分钟左右。吃完饭后继续地推工作,没有所谓的固定中午午休时间。下午6点下班后返回公司,不能直接下班,需要与同事交流话术,经理讲话洗脑。正常情况下9点下班。整个上班的一天中,早上到公司就是站着的,到晚上下班前都是站着。每天步数2万步以上。公司员工没有自己的工位,百来号人挤在一个20平方米的空间里听经理洗脑。白天就在市场上奔波,公司的投入成本几乎只有租金和工资,没有中央空调。早上2小时,晚上加班2小时,纯蒸桑拿。没有任何福利,节假日也没有3倍工资之类的。偶尔会有冲的酸梅汤和西瓜什么的。公司的晋升路径也很有意思:新人—组长—领队—主管—副经理—经理。要求是业绩和团队人数,类似传销模式,把人留下来。新人不能加微信、不能吐槽公司、不能有负面情绪、不能谈恋爱、不能说累。在公司没有任何坐的地方,不能依墙而坐。早上吃早饭在公司外面的安全通道,未到上班时间还会让你吃快些不能磨蹭。总之就是想榨干你。复试的时候,带你的师傅会给你营造一个钱多事少离家近的工作氛围,吹嘘工资有多高、还能吹自己毕业于好大学。然后让你早点来公司、无偿加班、抓住你可能不会走的心思进一步压榨你。总之,大家在找工作的时候一定要擦亮眼睛,避免踩坑!———来自网友
qq乃乃好喝到咩噗茶:不要做没有专业门槛的工作
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务