问题通过构建一个递归函数,随便取中间的一种情况,然后联系前面的情况,将50元和100元的人数设为变量即可。
这个实现的算法其实就是递归,通过递归函数实现。不过这里却是层层递归,每个递归下面都有多个分叉。第一个参数n很好理解,就是题目给的整数n,第二个参数k是题目说的把n分成k个数,题目求的是,能有多少种不重复的分法。
难理解的是第三个参数,什么鬼?
看第一幅图就知道了,其实这个参数是用来剪枝的,何谓剪呢?就是把每个递归下的分叉减少,以满足要求。
这里的要求是不重复,这就让我们每次都要求我们选择的第多少个数(反正不能大于k)的时候对于不能大于(或小于,看设定)前面选择的数。
有点费解是吧?看第三副图就知道了。这里的now就是起到这个作用的。用来记录你前面从小开始选的数,这次选的数不能小于它,小于的话有什么后果呢?就是和前面的重复了呗。至于为什么重复?递归看着好多层,你怎么知道重复?呃,这个,这个,还是举个栗子吧。
1 2 3 和2 1 3就是重复的,所以第二个选的数就不能比第一个选的数小,不然就重复的,而且一定会重复的。至于为什么,因为无数次的尝试告诉我,不可能不重复的。就不想真的去证明了,数学的东西,看的主要是感觉,真的证明起来就有点烦了。
第一个选的数就肯定是从1开始选啦,因为我们是从小到大排,1不小于1。一直选到不大于整数n/k为止。
那为什么不能大于整数n/k呢?
原因便是,每一次选的数都不能比前一次选的数小,所以吧,最多相等,所以每个数最大的就是n/k,再大就不行了,再大就会出现小的数,不平衡了。感受一下就知道了,无须证明的。
哇,那问题解决了哇,好简单,每次递归穷举,还可以剪掉重复的数,问题就解决了。那问题又来了。
前面的if(k==1)s++是什么鬼?
我们都知道s是用来计算次数的,这次数是根据最后面的子结点来决定的。所以算最后面的子结点就好了。我们知道,每次递归迭代,划分次数k都会减掉一次,所以呢,最后k为1的时候就不迭代递归了,就把每一次都给s加1,最后给记下来好了,就得到了方案个数。
后面又看到了这个奇怪的代码,这是什么操作呢?我们先看k==1的部分,除了s++外,还多了奇怪的代码段。
第三个参数好像也改了,之前我们用了记录所取数的下界,而现在好像用来做数组的下标,用数组来记录每种分法的结果。每次输出记录都是从最后结点开始的,那是递归完最后的数。
数组里面放的,也是来记录你前面从小开始选的数,然后最后输出。
还有一个不用三个参数的代码:
看到这个代码,其它的还好理解,可是里面的s=s+fXX要怎么理解呢?
第二个参数k-1很好理解,就是拆分的次数减1,因为已经选好一个数了。
可是,前面选的数怎么知道是(i-1)*k+1呢?
不懂就把数字代进去吧。初始的时候i等于1,这个数等于1,没毛病。
i等于2的时候,假设k为6,则这个数为7,这里透露着诡异。再看下面这个图。
其实就是简化了问题,没毛病。8分3份,第一份是2,则可分为2 1+ 1+,然后4可以继续分,
大家看到这个问题,挺类似的,依旧是递归,和前面的类似,区别只是,没有限制可以分为多少个数。所以后面选的数的限制最大只是n/2,只需要防止选的数不比n大就可以了。