n個の球をm個の箱に分ける方法

 投稿者:山中和義  投稿日:2013年11月20日(水)21時41分51秒
  問題:n個の球をm個の箱に分ける方法

(5) n<mなら0なので、n≧mのとき
同種類のn個の球と区別のつくm個の箱がある。
各箱に球を1個以上配る配り方は何通りあるか。
答え
n個の球を一列に並べて、(n-1)本の仕切り線を考える。
n=6の場合
   1   2   3   4   5 番目
 ○│○│○│○│○│○
(n-1)本の仕切り線から、(m-1)本を重複しないように選べばよい。comb(n-1,m-1)通り。
(終り)


PUBLIC NUMERIC N,M
LET N=5
LET M=3 !※M>1

DIM D(M-1) !仕切り線の位置

PUBLIC NUMERIC C !場合の数
LET C=0
CALL try(1,1,D)
PRINT C;"通り"

PRINT COMB(n-1,m-1);"通り"

END


EXTERNAL SUB try(P,S,D())
IF P=M THEN !R本目なら
   LET C=C+1

   !!!MAT PRINT D; !debug
   !PRINT D(1); !各箱の中の球の個数
   !FOR J=2 TO M-1
   !   PRINT D(J)-D(J-1);
   !NEXT J
   !PRINT N-D(M-1)

   PRINT STR$(C); ": "; !結果を表示する
   PRINT "["; !図示する
   FOR X=1 TO N
      PRINT "●";
      FOR J=1 TO M-1
         IF X=D(J) THEN PRINT "] ["; !1番目以降
      NEXT J
   NEXT X
   PRINT "]"
ELSE
   FOR i=S TO N-1 !p本目の仕切り線の位置 D(p)<D(p+1)
      LET D(P)=i
      CALL try(P+1,i+1,D)
   NEXT i
END IF
END SUB



(6)
同種類のn個の球と区別のつくm個の箱がある。
各箱に球を配る配り方(空箱があってよい)は何通りあるか。
答え
n個の球を一列に並べて、(n+1)本の仕切り線を考える。
n=6の場合
 0   1   2   3   4   5   6 番目
 │○│○│○│○│○│○│
(n+1)本の仕切り線から、(m-1)本を重複を許して選べばよい。H(n+1,m-1)通り。
(終り)


PUBLIC NUMERIC N,M
LET N=5
LET M=3 !※M>1

DIM D(M-1) !仕切り線の位置

PUBLIC NUMERIC C !場合の数
LET C=0
CALL try(1,0,D)
PRINT C;"通り"

PRINT COMB((N+1)+(M-1)-1,M-1);"通り" !H(N,R)=COMB(N+R-1,R)より

END


EXTERNAL SUB try(P,S,D())
IF P=M THEN !R本目なら
   LET C=C+1

   !!!MAT PRINT D; !debug
   !PRINT D(1); !各箱の中の球の個数
   !FOR J=2 TO M-1
   !   PRINT D(J)-D(J-1);
   !NEXT J
   !PRINT N-D(M-1)

   PRINT STR$(C); ": "; !結果を表示する
   PRINT "["; !図示する
   FOR J=1 TO M-1
      IF D(J)=0 THEN PRINT "] ["; !0番目の仕切り線
   NEXT J
   FOR X=1 TO N
      PRINT "●";
      FOR J=1 TO M-1
         IF X=D(J) THEN PRINT "] ["; !1番目以降
      NEXT J
   NEXT X
   PRINT "]"
ELSE
   FOR i=S TO N !p本目の仕切り線の位置 D(p)≦D(p+1)
      LET D(P)=i
      CALL try(P+1,i,D)
   NEXT i
END IF
END SUB



---------------------------------------------------

関係図 「k個の球を配る」による
 (5):1,n-m  ※初期値, 残り
 (6):0,n


!(5) n<mなら0なので、n≧mのとき
!同種類のn個の球と区別のつくm個の箱がある。
!各箱に球を1個以上配る配り方は何通りあるか。
!答え
!m個の箱に1個ずつ球を入れる。残り(n-m)個の球について、(6)を議論する。
!(終り)

PUBLIC NUMERIC N,M
LET N=5
LET M=3

DIM B(M) !各箱の中の球の個数
MAT B=CON

PUBLIC NUMERIC C !場合の数
LET C=0
CALL try(1,N-M,B)
PRINT C;"通り"

PRINT COMB(N-1,M-1);"通り"

PRINT


!(6)
!同種類のn個の球と区別のつくm個の箱がある。
!各箱に球を配る配り方(空箱があってよい)は何通りあるか。
!答え
!1番目の箱にi=0~n個を入れられる。
!2番目の箱にJ=0~(n-i)個を入れられる。
!3番目の箱にK=0~(n-(i+J))個を入れられる。
! :
! :
!(終り)

MAT B=ZER
LET C=0
CALL try(1,N,B)
PRINT C;"通り"

PRINT COMB((N+1)+(M-1)-1,M-1);"通り" !H(N,R)=COMB(N+R-1,R)より

END


EXTERNAL SUB try(P,T,B())
IF P=M THEN !R番目なら
   LET B(P)=B(P)+T !set it

   LET C=C+1

   MAT PRINT B; !各箱の中の球の個数

   FOR J=1 TO M !図示する
      PRINT "[";
      FOR X=1 TO B(J)
         PRINT "●";
      NEXT X
      PRINT "]";
   NEXT J
   PRINT

   LET B(P)=B(P)-T !restore it
ELSE
   FOR i=0 TO T !p番目
      LET B(P)=B(P)+i !set it

      CALL try(P+1,T-i,B)

      LET B(P)=B(P)-i !restore it
   NEXT i
END IF
END SUB



 

Re: n個の球をm個の箱に分ける方法

 投稿者:山中和義  投稿日:2013年11月21日(木)09時35分48秒
  > No.3203[元記事へ]

問題:n個の球をm個の箱に分ける方法

関係図 m進法n桁の数による
    0
  (2) → (1)
  f↓  ↓f
  (4) → (3)
    0
とする手法があるが、m^nが10^9程度になると、場合の数を数え上げるのが困難になる。

そこで、条件に合うm進法n桁の数を生成することを考える。

答え (3)
(7)の結果より、箱の中の球の個数は、[●] [●] [●●●] と [●] [●●] [●●] の2通り。

[●] [●] [●●●] の場合
 箱の番号 1,2,3,3,3 と考えると、
  5!/(1!1!3!)=20通り
 は、3進法5桁(各位の数は1,2,3とする)の並び方となる。例 12333, 13233,13323,…,33321
 1個の並び2!=2通りが重複する(例 ①②333と②①333)ので、20/2=10通り

[●] [●●] [●●] の場合
 1,2,2,3,3 と考えると、5!/(1!2!2!)=30通り
 2個の並び2!=2通りが重複するので、30/2=15通り

よって、10+15=25通りとなる。
(終り)


関係図 同じものを含む順列
 (5):1 → (1)
 (6):0 → (2)

 (7):1 → (3)
 (8):0 → (4)

以上を、プログラムに反映させる。


!(1) n<mなら0なので、n≧mのとき
!相異なるn個の球と区別のつくm個の箱がある。
!各箱に球を1個以上配る配り方は何通りあるか。

PUBLIC NUMERIC N,M
LET N=5
LET M=3

DIM A(N) !n個の球 値は、箱の番号
DIM B(M) !m個の箱 値は、球の個数

PUBLIC NUMERIC C !場合の数
LET C=0
CALL try(1,1,N,A,B)
PRINT C;"通り"

PRINT FACT(m)*StirlingS2(n,m);"通り" !検算

PRINT


!(2)
!相異なるn個の球と区別のつくm個の箱がある。
!各箱に球を配る配り方(空箱があってよい)は何通りあるか。

LET C=0
CALL try(1,0,N,A,B)
PRINT C;"通り"

PRINT M^N;"通り" !検算

END


EXTERNAL SUB try(P,S,T,A(),B())
IF P>M THEN !最後の箱まで配って、
   IF T=0 THEN !球を残らず配り終えたなら
      CALL stub(N,M,A,B)
   END IF
ELSE
   FOR i=S TO T !p番目の箱 B(1)≦B(2)≦B(3)≦…≦B(p)
      LET B(P)=i
      CALL try(P+1,S,T-i,A,B) !(5),(6)
   NEXT i
END IF
END SUB


EXTERNAL SUB stub(N,M,A(),B()) !同じ球● を 異なる球① へ
LET K=0 !最初のパターン
FOR J=1 TO M
   FOR X=1 TO B(J)
      LET A(K+X)=J
   NEXT X
   LET K=K+B(J)
NEXT J
MAT PRINT A; !debug

DO
   LET C=C+1

   PRINT STR$(C); ": "; !結果を表示する
   FOR J=1 TO M !j番目の箱
      PRINT "[";
      FOR K=1 TO N
         IF A(K)=J THEN PRINT K; !球の番号
      NEXT K
      PRINT "]";
   NEXT J
   PRINT

   CALL NextPermFactorial(A,N, rc) !次へ
LOOP UNTIL rc<>0
END SUB


EXTERNAL SUB NextPermFactorial(A(),N, rc) !辞書式順序で次の順列を返す ※「異なるn個のもの」と共通
LET i=N-1 !順列を右から左にみて、増加列から減少列に変わる位置iを探す
DO WHILE i>0 AND A(i)>=A(i+1) !0は番人
   LET i=i-1
LOOP
IF i=0 THEN !A(1)>A(2)>A(3)> … >A(N)なら 例. N=4、4,3,2,1
   LET rc=1 !完了(最後の並びである)
   EXIT SUB
END IF

LET j=N !その位置iより右で、A(i)以上で最小の数A(j)を探す
DO WHILE A(i)>=A(j)
   LET j=j-1
LOOP
LET t=A(i) !A(i)とA(j)を交換する
LET A(i)=A(j)
LET A(j)=t

LET i=i+1 !(i+1)からNまでの範囲を逆順にする
LET j=N
DO WHILE i<j
   LET t=A(i) !swap it
   LET A(i)=A(j)
   LET A(j)=t
   LET i=i+1
   LET j=j-1
LOOP
LET rc=0 !未了
END SUB


EXTERNAL FUNCTION StirlingS2(n,m) !第2種スターリング数 ※公式による
LET s=0
FOR k=0 TO m-1 !包除原理より
   LET s=s+(-1)^k*COMB(m,k)*(m-k)^n
NEXT k
LET StirlingS2=s/FACT(m)
END FUNCTION



上記をベースに考える。青色の字は修正、赤色の字は追加して、


!(3) n<mなら0なので、n≧mのとき
!相異なるn個の球と区別のつかないm個の箱がある。
!各箱に球を1個以上配る配り方は何通りあるか。

PUBLIC NUMERIC N,M
LET N=5
LET M=3

DIM A(N) !n個の球 値は、箱の番号
DIM B(M) !m個の箱 値は、球の個数

PUBLIC NUMERIC C !場合の数
LET C=0
CALL try(1,1,N,A,B)
PRINT C;"通り"

PRINT StirlingS2(n,m);"通り" !検算

PRINT


!(4)
!相異なるn個の球と区別のつかないm個の箱がある。
!各箱に球を配る配り方(空箱があってよい)は何通りあるか。

LET C=0
CALL try(1,0,N,A,B)
PRINT C;"通り"

LET S=0 !検算
FOR k=1 TO M
   LET S=S+StirlingS2(n,k)
NEXT k
PRINT S;"通り"

END


EXTERNAL SUB try(P,S,T,A(),B())
IF P>M THEN !最後の箱まで配って、
   IF T=0 THEN !球を残らず配り終えたなら
      CALL stub(N,M,A,B)
   END IF
ELSE
   FOR i=S TO T !p番目の箱 B(1)≦B(2)≦B(3)≦…≦B(p)
      LET B(P)=i
      CALL try(P+1,i,T-i,A,B) !(7),(8)
   NEXT i
END IF
END SUB


EXTERNAL SUB stub(N,M,A(),B()) !同じ球● を 異なる球① へ
LET K=0 !最初のパターン(m進法n桁)
FOR J=1 TO M
   FOR X=1 TO B(J)
      LET A(K+X)=J
   NEXT X
   LET K=K+B(J)
NEXT J
MAT PRINT A; !debug

DO
   CALL Filter(N,M,A,B, rc) !箱の中の球の並びで篩う
   IF rc<>0 THEN


      LET C=C+1

      PRINT STR$(C); ": "; !結果を表示する
      FOR J=1 TO M !j番目の箱
         PRINT "[";
         FOR K=1 TO N
            IF A(K)=J THEN PRINT K; !球の番号
         NEXT K
         PRINT "]";
      NEXT J
      PRINT

   END IF
   CALL NextPermFactorial(A,N, rc) !次へ
LOOP UNTIL rc<>0
END SUB


EXTERNAL SUB Filter(N,M,A(),B(), rc) !個数が同じ箱の並びが昇順になっているかどうあ確認する
DIM F(M) !m個の箱 値は、球の番号で最小のもの

LET rc=0 !NG

!中身(球の並び)について、
! [①][②][③4][⑤6] と [①][②][⑤6][③4] を同一とみなす必要がある。
FOR J=1 TO M !j番目の箱
   FOR K=1 TO N !球の番号で最小のもの
      IF A(K)=J THEN EXIT FOR
   NEXT K
   LET F(J)=K !空の場合は、N+1
NEXT J
!!!MAT PRINT F; !debug

FOR K=1 TO N !球の個数が同じものでは
   LET W=-1
   FOR J=1 TO M !j番目の箱
      IF B(J)=K THEN
         IF F(J)<W THEN EXIT FOR !球の番号が昇順のもの
         LET W=F(J)
      END IF
   NEXT J
   IF J<=M THEN EXIT FOR
NEXT K
IF K>N THEN LET rc=-1 !OK
END SUB



EXTERNAL SUB NextPermFactorial(A(),N, rc) !辞書式順序で次の順列を返す ※「異なるn個のもの」と共通
LET i=N-1 !順列を右から左にみて、増加列から減少列に変わる位置iを探す
DO WHILE i>0 AND A(i)>=A(i+1) !0は番人
   LET i=i-1
LOOP
IF i=0 THEN !A(1)>A(2)>A(3)> … >A(N)なら 例. N=4、4,3,2,1
   LET rc=1 !完了(最後の並びである)
   EXIT SUB
END IF

LET j=N !その位置iより右で、A(i)以上で最小の数A(j)を探す
DO WHILE A(i)>=A(j)
   LET j=j-1
LOOP
LET t=A(i) !A(i)とA(j)を交換する
LET A(i)=A(j)
LET A(j)=t

LET i=i+1 !(i+1)からNまでの範囲を逆順にする
LET j=N
DO WHILE i<j
   LET t=A(i) !swap it
   LET A(i)=A(j)
   LET A(j)=t
   LET i=i+1
   LET j=j-1
LOOP
LET rc=0 !未了
END SUB


EXTERNAL FUNCTION StirlingS2(n,m) !第2種スターリング数 ※公式による
LET s=0
FOR k=0 TO m-1 !包除原理より
   LET s=s+(-1)^k*COMB(m,k)*(m-k)^n
NEXT k
LET StirlingS2=s/FACT(m)
END FUNCTION


 

Re: n個の球をm個の箱に分ける方法

 投稿者:山中和義  投稿日:2013年11月23日(土)21時09分20秒
  > No.3203[元記事へ]

重複組合せ → 組合せ


!(6)
!同種類のn個の球と区別のつくm個の箱がある。
!各箱に球を配る配り方(空箱があってよい)は何通りあるか。
!答え
!(終り)

PUBLIC NUMERIC N,M
LET N=5
LET M=3

PUBLIC NUMERIC C !場合の数
LET C=0

LET t=N !C(n+m-1,n)=C(n+m-1,m-1)
LET N=N+M-1
LET M=t

DIM A(N)
CALL comb(A,1,M)
PRINT C;"通り"

END

!SAMPLEフォルダ内 COMBINAT.BAS より

EXTERNAL SUB comb(a(),k,r) !1~nの集合からr個を選ぶ組合せを生成する
IF r=0 THEN
   LET C=C+1
   FOR i=1 TO N
      IF a(i)=1 THEN PRINT i;
   NEXT i
   PRINT " → ";
   LET k=0 !n個の球 値は、箱の番号
   FOR i=1 TO N
      IF a(i)=1 THEN
         PRINT i-k; !0,1,2,3,…,r-1が加味されているので
         LET k=k+1
      END IF
   NEXT i

   PRINT
ELSE
   FOR i=k TO N-r+1!k以降の数からr個を選択する
      LET a(i)=1 !2進法n桁とみなし、iビット目を1とする
      CALL comb(a,i+1,r-1)
      LET a(i)=0 !元に戻す
   NEXT i
END IF
END SUB


実行結果

1  2  3  4  5  →  1  1  1  1  1
1  2  3  4  6  →  1  1  1  1  2
1  2  3  4  7  →  1  1  1  1  3
1  2  3  5  6  →  1  1  1  2  2
1  2  3  5  7  →  1  1  1  2  3
1  2  3  6  7  →  1  1  1  3  3
1  2  4  5  6  →  1  1  2  2  2
1  2  4  5  7  →  1  1  2  2  3
1  2  4  6  7  →  1  1  2  3  3
1  2  5  6  7  →  1  1  3  3  3
1  3  4  5  6  →  1  2  2  2  2
1  3  4  5  7  →  1  2  2  2  3
1  3  4  6  7  →  1  2  2  3  3
1  3  5  6  7  →  1  2  3  3  3
1  4  5  6  7  →  1  3  3  3  3
2  3  4  5  6  →  2  2  2  2  2
2  3  4  5  7  →  2  2  2  2  3
2  3  4  6  7  →  2  2  2  3  3
2  3  5  6  7  →  2  2  3  3  3
2  4  5  6  7  →  2  3  3  3  3
3  4  5  6  7  →  3  3  3  3  3
21 通り


---------------------------------------


!(6)
!同種類のn個の球と区別のつくm個の箱がある。
!各箱に球を配る配り方(空箱があってよい)は何通りあるか。
!答え
!(終り

PUBLIC NUMERIC N,M
LET N=5
LET M=3

DIM A(N+M-1) !n個の球と(m-1)個の仕切り線
FOR i=1 TO N !最初の並び(同じものを含む順列)
   LET A(i)=1
NEXT i
FOR i=N+1 TO N+M-1
   LET A(i)=2
NEXT i
MAT PRINT A;

LET C=0 !場合の数
DO
   LET C=C+1

   PRINT STR$(C); ": "; !結果を表示する
   PRINT "[";
   FOR K=1 TO N+M-1
      IF A(K)=1 THEN PRINT "●";
      IF A(K)=2 THEN PRINT "][";
   NEXT K
   PRINT "]";
   PRINT

   CALL NextPermFactorial(A,N+M-1, rc) !次へ
LOOP UNTIL rc<>0
PRINT C;"通り"

PRINT COMB(n+m-1,m-1);"通り"

END


EXTERNAL SUB NextPermFactorial(A(),N, rc) !辞書式順序で次の順列を返す ※「異なるn個のもの」と共通
LET i=N-1 !順列を右から左にみて、増加列から減少列に変わる位置iを探す
DO WHILE i>0 AND A(i)>=A(i+1) !0は番人
   LET i=i-1
LOOP
IF i=0 THEN !A(1)>A(2)>A(3)> … >A(N)なら 例. N=4、4,3,2,1
   LET rc=1 !完了(最後の並びである)
   EXIT SUB
END IF

LET j=N !その位置iより右で、A(i)以上で最小の数A(j)を探す
DO WHILE A(i)>=A(j)
   LET j=j-1
LOOP
LET t=A(i) !A(i)とA(j)を交換する
LET A(i)=A(j)
LET A(j)=t

LET i=i+1 !(i+1)からNまでの範囲を逆順にする
LET j=N
DO WHILE i<j
   LET t=A(i) !swap it
   LET A(i)=A(j)
   LET A(j)=t
   LET i=i+1
   LET j=j-1
LOOP
LET rc=0 !未了
END SUB


実行結果

1  1  1  1  1  2  2

1: [●●●●●][][]
2: [●●●●][●][]
3: [●●●●][][●]
4: [●●●][●●][]
5: [●●●][●][●]
6: [●●●][][●●]
7: [●●][●●●][]
8: [●●][●●][●]
9: [●●][●][●●]
10: [●●][][●●●]
11: [●][●●●●][]
12: [●][●●●][●]
13: [●][●●][●●]
14: [●][●][●●●]
15: [●][][●●●●]
16: [][●●●●●][]
17: [][●●●●][●]
18: [][●●●][●●]
19: [][●●][●●●]
20: [][●][●●●●]
21: [][][●●●●●]
21 通り
21 通り


---------------------------------------


!(5) n<mなら0なので、n≧mのとき
!同種類のn個の球と区別のつくm個の箱がある。
!各箱に球を1個以上配る配り方は何通りあるか。

PUBLIC NUMERIC N,M
LET N=5
LET M=3

DIM B(M) !各箱の中の球の個数

PUBLIC NUMERIC C !場合の数
LET C=0
CALL try(1,N,B)
PRINT C;"通り"

PRINT COMB(n-1,m-1);"通り"

PRINT


!(6)
!同種類のn個の球と区別のつくm個の箱がある。
!各箱に球を配る配り方(空箱があってよい)は何通りあるか。
!答え

! 関係図 「k個の球を配る」による
!  (6):n+m,m → (5)
!(終り)

LET C=0
CALL try(1,N+M,B)
PRINT C;"通り"

PRINT COMB(n+m-1,m-1);"通り"

END


EXTERNAL SUB try(P,T,B())
IF P>M THEN !最後の箱まで配って、
   IF T=0 THEN !球を残らず配り終えたなら
      LET C=C+1

      PRINT STR$(C); ": "; !結果を表示する
      FOR J=1 TO M !図示する
         PRINT "[○";
         FOR X=2 TO B(J)
            PRINT "●";
         NEXT X
         PRINT "]";
      NEXT J
      PRINT
   END IF
ELSE
   FOR i=1 TO T !p番目の箱
      LET B(P)=i
      CALL try(P+1,T-i,B)
   NEXT i
END IF
END SUB


実行結果

1: [○][○][○●●]
2: [○][○●][○●]
3: [○][○●●][○]
4: [○●][○][○●]
5: [○●][○●][○]
6: [○●●][○][○]
6 通り
6 通り

1: [○][○][○●●●●●]
2: [○][○●][○●●●●]
3: [○][○●●][○●●●]
4: [○][○●●●][○●●]
5: [○][○●●●●][○●]
6: [○][○●●●●●][○]
7: [○●][○][○●●●●]
8: [○●][○●][○●●●]
9: [○●][○●●][○●●]
10: [○●][○●●●][○●]
11: [○●][○●●●●][○]
12: [○●●][○][○●●●]
13: [○●●][○●][○●●]
14: [○●●][○●●][○●]
15: [○●●][○●●●][○]
16: [○●●●][○][○●●]
17: [○●●●][○●][○●]
18: [○●●●][○●●][○]
19: [○●●●●][○][○●]
20: [○●●●●][○●][○]
21: [○●●●●●][○][○]
21 通り
21 通り




 

戻る