(算法)李白喝酒

发表在    程序里的星辰与大海 08-25 23:11:53

0 2981 3

https://segmentfault.com/q/1010000000443863

本贴是对上述地址的问题思考。

问题:

李白街上走,提壶去买酒,遇店加一倍,见花喝一斗。途中遇5次店,见10次花,壶中原有2斗酒,最后刚好遇见花,刚好喝完酒,求可能的解。


分析:从两个角度去分析,一个是人的角度,另一个是计算机角度。

人的角度:把问题抽象成数学问题求解,确定一些关系。

1.共见花10次=-10(斗酒),原有2斗酒=2,即增加的酒是-(-10+2)=8(斗酒)

问题变成了在五次中增加8斗酒的可能解(遇店=加酒=1,见花=减酒=0,即对5个1和10个0进行排列组合,最后一次是0。由于见花不存在顺序的区别,所以只需要把遇店的可能情况排出来再填入见花即可,所以五次中增加8斗酒的可能解就是最终整个问题的可能解数)

2.增加的酒数要满足5次一共加8斗,注定了增加的酒数不能大于4(五次中每次都加1斗酒是最少的,还剩下3斗,全部加到其中一次就是4斗,即一次最大只能加4斗)。

综合上述两点,我们可以有:

11222/11132/11114这三种可能,

那么这三种可能是否有不成立的呢(下面说的“基数”指翻倍前的酒数)?

对于11114:

要想增加4斗酒,就必须有基数4去翻倍。基数是4的可能情况有:

A.原先有2斗酒,遇店后变成4斗

此时必须有24,而11114中没有2,所以不可能。

B.原先有n(n≥5)斗酒,遇花后变成4斗再遇店

原先有2斗,已经增加了至少3斗酒(n-2≥3),还要增加4斗,则一共增加了3+4=7斗,也就是说,要遇店4次加7斗酒(还有一次加1斗才满足5次加8斗的条件),其中有一次是加4斗的,也就是遇店3次加3斗,而这是不可能的(相当于1次加1斗,而1次加1斗意味着基数是1,那么又怎么能有n斗酒出现呢?n可是大于等于5的!)。综上,11114的情况是不可能的。

(其实看到1111就知道不可能了,增加1斗酒,基数必须是1,四个基数都是1,后面不可能基数变成4出现增加1斗酒的情况。这是我后来才发现的....)

11222是可能的,保持基数是2和1是很容易的事情。

11132,要想增加3斗酒,就必须有基数3去翻倍,所以不可能是连续三个1在3前面,必须是23连着才行。

至此,我们知道了可能的情况是11222,32111.利用高中的排列组合,我们可以有:

11222的可能情况是C25,32111的可能情况是C14,加起来一共14种可能。


计算机角度:函数与条件

设J=酒,D=遇店剩余次数,H=见花剩余次数

初始条件可列:

J=2,D=5,H=10;最后一次是H;J=0,D=0,H=0

其它条件可列:

F(J,H,D)

F(0,H≠0,D≠0),false;F(J≠0,0,D≠0),false;(不能只有J=H=D=0才true,这样就是暴力递归而非用剪枝条件优化算法。什么是暴力递归和剪枝条件看开头的网址)

F(J,H(J>H),D),false;F(J,H(J·2^D<H),D),false

然后是函数关系:

H=H-1时,F=F(J-1,H,D);D=D-1时,F=F(2J,H,D)

用if循环来递归就可以得出解了。详细的代码在开头的网址里有。(有空我会用C++实现,然后补充进这个帖子)




回顾上面两个角度,我发现所谓算法,和人的角度本质上是一样的:人在思考的时候往往一开始也是用穷举的方法去思考,只不过我们没有那么死板,我们会用“剪枝”(开头的文章地址中提到的一个词)去把一些不对的方法给删去(比如上文我通过一系列的演算把11114这条去掉了)。而计算机的算法就是在继续人“剪枝”后的穷举。

以上所有,就是我在李白喝酒问题中学到的思维与方法。




登录或注册后发布评论