简单的stirling数(扩展)
考虑这样一种情况,将前面容器的数量设置为k,将n个球放入其中,要求非空;
先从数学的角度看,与前面的处理方式类似,假设选取第一个数作为支点,下面将存在两种情况,假设这个支点单独放在一个盒子里,没有与另外的数字在一起,那可能性为C(k-1,n-1),或者它有可能与其他的在一起,而这里的这种可能显然是C(k,n-1)中的k中可能子集中的一种,但k种可能都存在,所以是k*C(k,n-1),故有如下数学公式成立:
C(k,n)=C(k-1,n-1)+k*C(k,n-1)
下面写程序来证明:
(defun formula (k n)
(if (eq k 1)
1
(if (eq k n)
1
(+ (formula (1- k)
(1- n))
(* k
(formula k
(1- n)))))))
(defun pow (num count)
(if (or (> count 1) (eq count 1) )
(* num
(pow num
(- count 1) ) )
1))
(defun slayer ( count)
(if (or (> count 1) (eq count 1) )
(* count
(slayer
(- count 1) ) )
1))
(defun checklst (lst)
(if (eq lst nil)
T
(if (eq (car lst) 0)
nil
(checklst (cdr lst)))))
(defun addone (n k temp left )
(if (eq temp 0)
0
(progn
(+
(expr n
k
(carth temp (copy left)))
(addone n
k
(1- temp)
(carth temp (copy left)))))))
(defun strlen (lst)
(if (eq lst nil)
0
(1+ (strlen (cdr lst)))))
(defun copy (lst)
(if (eq lst nil)
nil
(cons (car lst)
(copy (cdr lst)))))
(defun carth (num lst)
(if (eq num 1)
(cons (incf (car lst))
(cdr lst))
(cons (car lst)
(carth (1- num)
(cdr lst)))))
(defun expr (n k left)
(if (eq n k )
1
(if (< n k )
0
(if (and (eq k 0)
(not (eq n 0)))
0
(if (and (> n 0)
(not (eq k 0 )))
(+ (expr (1- n)
(1- k)
(carth k (copy left)))
(addone (1- n)
k
k
(copy left)))
(if (checklst (print left))
1
0))))))
(defun genlst (k)
(if (eq k 0)
nil
(cons 0
(genlst (1- k)))))
特别注意其中expr参数的变化
(defun test (n k)
(if (or (> n k) (eq n k))
(progn
(print (expr n k (genlst k)))
(print 'compare)
(print (formula k n ))
(test (- n 1) k))
(print 'over)))
[76]> (test 10 2)
511
COMPARE
511
255
COMPARE
255
127
COMPARE
127
63
COMPARE
63
31
COMPARE
31
15
COMPARE
15
7
COMPARE
7
3
COMPARE
3
1
COMPARE
1
OVER
OVER
[77]> (test 10 3)
9330
COMPARE
9330
3025
COMPARE
3025
966
COMPARE
966
301
COMPARE
301
90
COMPARE
90
25
COMPARE
25
6
COMPARE
6
1
COMPARE
1
OVER
OVER
[78]> (test 10 4)
34105
COMPARE
34105
7770
COMPARE
7770
1701
COMPARE
1701
350
COMPARE
350
65
COMPARE
65
10
COMPARE
10
1
COMPARE
1
OVER
OVER
在盒子数量分别为2,3,4的时候,注意可以发现最终程序所得到的结果与用数学公式得到的结果是一样的,表示我们的计算过程是正确的。
另外特别注意程序中的k表示盒子数量,left表示每个盒子中装的数字的个数;特别是在expr的代码中:
(expr (1- n)
(1- k)
(carth k (copy left)))
(addone (1- n)
k
k
(copy left)))
分别对应于数学公式中对应的两种情况的考虑,一种表示当前的数字与后面的数字没有在一个盒子里的,和其中有重复的现象;并通过这段代码隐形地给盒子排了个序,因为盒子是无区别的,这种排序对结果无影响。从左到右k个盒子,我们假设从最右边的盒子开始,考虑第n个数,做为第一种情况是对应的left的第k位加1;第二种情况是采用addone函数,考虑前面任意k个位置加1的情况。
考虑这样一种情况,将前面容器的数量设置为k,将n个球放入其中,要求非空;
先从数学的角度看,与前面的处理方式类似,假设选取第一个数作为支点,下面将存在两种情况,假设这个支点单独放在一个盒子里,没有与另外的数字在一起,那可能性为C(k-1,n-1),或者它有可能与其他的在一起,而这里的这种可能显然是C(k,n-1)中的k中可能子集中的一种,但k种可能都存在,所以是k*C(k,n-1),故有如下数学公式成立:
C(k,n)=C(k-1,n-1)+k*C(k,n-1)
下面写程序来证明:
(defun formula (k n)
(if (eq k 1)
1
(if (eq k n)
1
(+ (formula (1- k)
(1- n))
(* k
(formula k
(1- n)))))))
(defun pow (num count)
(if (or (> count 1) (eq count 1) )
(* num
(pow num
(- count 1) ) )
1))
(defun slayer ( count)
(if (or (> count 1) (eq count 1) )
(* count
(slayer
(- count 1) ) )
1))
(defun checklst (lst)
(if (eq lst nil)
T
(if (eq (car lst) 0)
nil
(checklst (cdr lst)))))
(defun addone (n k temp left )
(if (eq temp 0)
0
(progn
(+
(expr n
k
(carth temp (copy left)))
(addone n
k
(1- temp)
(carth temp (copy left)))))))
(defun strlen (lst)
(if (eq lst nil)
0
(1+ (strlen (cdr lst)))))
(defun copy (lst)
(if (eq lst nil)
nil
(cons (car lst)
(copy (cdr lst)))))
(defun carth (num lst)
(if (eq num 1)
(cons (incf (car lst))
(cdr lst))
(cons (car lst)
(carth (1- num)
(cdr lst)))))
(defun expr (n k left)
(if (eq n k )
1
(if (< n k )
0
(if (and (eq k 0)
(not (eq n 0)))
0
(if (and (> n 0)
(not (eq k 0 )))
(+ (expr (1- n)
(1- k)
(carth k (copy left)))
(addone (1- n)
k
k
(copy left)))
(if (checklst (print left))
1
0))))))
(defun genlst (k)
(if (eq k 0)
nil
(cons 0
(genlst (1- k)))))
特别注意其中expr参数的变化
(defun test (n k)
(if (or (> n k) (eq n k))
(progn
(print (expr n k (genlst k)))
(print 'compare)
(print (formula k n ))
(test (- n 1) k))
(print 'over)))
[76]> (test 10 2)
511
COMPARE
511
255
COMPARE
255
127
COMPARE
127
63
COMPARE
63
31
COMPARE
31
15
COMPARE
15
7
COMPARE
7
3
COMPARE
3
1
COMPARE
1
OVER
OVER
[77]> (test 10 3)
9330
COMPARE
9330
3025
COMPARE
3025
966
COMPARE
966
301
COMPARE
301
90
COMPARE
90
25
COMPARE
25
6
COMPARE
6
1
COMPARE
1
OVER
OVER
[78]> (test 10 4)
34105
COMPARE
34105
7770
COMPARE
7770
1701
COMPARE
1701
350
COMPARE
350
65
COMPARE
65
10
COMPARE
10
1
COMPARE
1
OVER
OVER
在盒子数量分别为2,3,4的时候,注意可以发现最终程序所得到的结果与用数学公式得到的结果是一样的,表示我们的计算过程是正确的。
另外特别注意程序中的k表示盒子数量,left表示每个盒子中装的数字的个数;特别是在expr的代码中:
(expr (1- n)
(1- k)
(carth k (copy left)))
(addone (1- n)
k
k
(copy left)))
分别对应于数学公式中对应的两种情况的考虑,一种表示当前的数字与后面的数字没有在一个盒子里的,和其中有重复的现象;并通过这段代码隐形地给盒子排了个序,因为盒子是无区别的,这种排序对结果无影响。从左到右k个盒子,我们假设从最右边的盒子开始,考虑第n个数,做为第一种情况是对应的left的第k位加1;第二种情况是采用addone函数,考虑前面任意k个位置加1的情况。