常见的lisp中的整数分区

时间:2016-07-03 13:58:05

标签: common-lisp maple

移植一个接受整数的函数并吐出该数字的整数分区,即

((4) (3 1) (2 2) (2 1 1) (1 1 1 1))

应该产生

row

也就是说,分区列表首先由最大部分排序,然后是第二大部分,等等。并且总和是我们正在分区的整数。

在John Stembridge的枫包SF中,这是由以下子程序产生的,该子程序在由colSF/Par/sub(n,n,n)定义的框内生成带有图表的分区,以便`SF/Par/sub`:=proc(n,row,col) local i; if n=0 then [[]] elif col=0 then [] else [seq(op(map((x,y)->[y,op(x)],`SF/Par/sub`(n+i,-i,col-1),-i)), i=-min(row,n)..-iquo(n+col-1,col))] fi end: 就是我想:

(floor (/ x y))

其中iquo是(2 (2 ()) (1 (1 ())))

问题是如何从

获得
((2 2) (2 1 1))

结果

(defun partitions (n row col)
  ""
  (block nil
    (if (= n 0) (return '(())))
    (if (= col 0) (return '()))
    (loop for i from (- (min row n)) to (floor (/ (- (+ n col) 1) col))
       collect (cons (- i) (partitions (+ n i) (- i) (- col 1))))))

修改

以下是我的尝试

(partitions 3 3 3)

它运行并终止,但我能说的就是它。

((3 NIL) (2 (1 NIL) (0 (0) (-1)) (-1 (-1) (-2))) (1 (1 (1 NIL) (0) (-1)) (0 (0) (-1) (-2)) (-1 (-1) (-2) (-3))) (0 (0 (0) (-1) (-2) (-3)) (-1 (-1) (-2) (-3) (-4)) (-2 (-2) (-3) (-4) (-5))) (-1 (-1 (-1) (-2) (-3) (-4) (-5)) (-2 (-2) (-3) (-4) (-5) (-6)))) 收益

((3) (2 1) (1 1 1))

我希望它返回{{1}}

2 个答案:

答案 0 :(得分:4)

由于你已经得到了一个有效的答案,这里有一些关于你的编码风格的评论:

(defun partitions (n row col)
  ""
  (block nil
    (if (= n 0) (return '(())))
    (if (= col 0) (return '()))
    (loop for i from (- (min row n)) to (floor (/ (- (+ n col) 1) col))
       collect (cons (- i) (partitions (+ n i) (- i) (- col 1))))))

""可以省略,因为它没用,也不包含文档。

DEFUN已经设置了一个块,但它被命名为partitions。所以

(defun partitions (...)
   (block nil ... (return ...) ...)

将是

(defun partitions (...)
   ...
   (return-from partitions ...)
   ...)

(if (foo) (bar))通常写为(when (foo) (bar))。 因为(if (foo) (progn (bar) (baz)))(when (foo) (bar) (baz))

在Lisp中使用(block ... (if ... (return ...)) (if ... (return...)...)是不常见的。 IF通常会返回一个值,因此不需要使用RETURNRETURN-FROM的其他控制流。而不是

  (block nil
    (if (= n 0) (return '(())))
    (if (= col 0) (return '()))
    (loop for i from (- (min row n)) to (floor (/ (- (+ n col) 1) col))
       collect (cons (- i) (partitions (+ n i) (- i) (- col 1))))))

一个人会写:

(if (= n 0)
    '(())
  (if (= col 0)
      '()
    (loop for i from (- (min row n)) to (floor (/ (- (+ n col) 1) col))
          collect (cons (- i) (partitions (+ n i) (- i) (- col 1))))))

由于这些嵌套的If在Lisp代码中非常常见,因此cond结构使编写起来更容易一些。代码也不会通过每个子句向右移动:

(cond ((= n 0)
       '(()))
      ((= col 0)
       '())
      (t
       (loop for i from (- (min row n)) to (floor (/ (- (+ n col) 1) col))
             collect (cons (- i) (partitions (+ n i) (- i) (- col 1))))))

答案 1 :(得分:3)

您应该使用BLOCK代替RETURN / (defun partitions (n row col) (cond ((= n 0) ...) ((= col 0) ...) (t (loop ...))))

ZEROP

然后,您可以使用(= X 0)代替1-(- X 1)代替I。我也没有看到任何理由让DOWNTO为否定(你可以使用循环关键字FLOOR倒计时)。 (FLOOR X Y)将除数作为可选参数,因此您可以编写(FLOOR (/ X Y))而不是(defun partitions (n row col) "" (cond ((zerop n) '(())) ((zerop col) '()) (t (loop for i from (min row n) downto (floor (1- (+ n col)) col) collect (cons i (partitions (- n i) i (1- col))))))) (partitions 3 3 3) ;=> ((3 NIL) (2 (1 NIL)) (1 (1 (1 NIL))))

通过以下更改:

NIL

这些COND是由NIL的第一个子句中的嵌套列表引起的。请记住,空列表与'()相同。如果您将其更改为((3) (2 (1)) (1 (1 (1)))),则结果为N

要删除那些额外的内部列表,您可以使用构建结果的内部函数,并在(defun partitions (n row col) "" (let ((result (list))) (labels ((%partitions (n row col acc) (cond ((zerop n) (push (reverse acc) result)) ((zerop col)) (t (loop for i from (min row n) downto (floor (1- (+ n col)) col) do (%partitions (- n i) i (1- col) (cons i acc))))))) (%partitions n row col '()) (nreverse result)))) (partitions 3 3 3) ;=> ((3) (2 1) (1 1 1)) (partitions 4 4 4) ;=> ((4) (3 1) (2 2) (2 1 1) (1 1 1 1)) 为零时将其推送到列表中。

(defun partitions (n)
  (let ((result (list)))
    (labels ((%partitions (n largest-number acc)
               (cond ((< n 1) (push (reverse acc) result))
                     (t (loop for l from largest-number downto 1
                              do (loop for i from (floor n l) downto 1
                                       do (%partitions
                                           (- n (* l i))
                                           (1- l)
                                           (append (make-list i :initial-element l)
                                                   acc))))))))
      (%partitions n n '())
      (nreverse result))))

(partitions 3)
;=> ((3) (2 1) (1 1 1))
(partitions 4)
;=> ((4) (3 1) (2 2) (2 1 1) (1 1 1 1))
(partitions 5)
;=> ((5) (4 1) (3 2) (3 1 1) (2 2 1) (2 1 1 1) (1 1 1 1 1))

稍长一点,但至少是IMO,更简单的方法来解决问题:

#include <stdio.h>
int main(){
    typedef struct Ds {
        int i1;
        int i2;
        char c1;
        int i3;
    } Ds;
    Ds ds; 
    sscanf("12,6,@,3","%d,%d,%c,%d",&ds.i1, &ds.i2, &ds.c1, &ds.i3);
    printf("%d,%d,%c,%d\n",ds.i1,ds.i2,ds.c1,ds.i3);
    return 0;
}