回答編集履歴

3

文面の微修正とコード添付

2021/01/06 10:07

投稿

swordone
swordone

スコア20669

test CHANGED
@@ -4,11 +4,11 @@
4
4
 
5
5
  「分配の仕方」は「仕切りの入れ方」ととらえることができます。
6
6
 
7
- そこで、「仕切りを入れる場所」として、0~(分配する数+分配する個数-2)の乱数を
7
+ そこで、「仕切りを入れる場所」として、0以上(分配する数+分配する個数-1)未満の乱数を
8
8
 
9
9
  重複しないように(分配する個数-1)個取れば、どの分け方も等確率で得られます。
10
10
 
11
- 例えば、例の場合、つまり10を3つに分配する場合、10+3-2=11なので、
11
+ 例えば、例の場合、つまり10を3つに分配する場合、10+3-1=12なので、
12
12
 
13
13
  0~11の12個から乱数を2つ取得します。
14
14
 
@@ -33,3 +33,109 @@
33
33
  分配する数より分配する個数が十分少なければ、逐次乱数を取り出して重複チェックするのでも
34
34
 
35
35
  十分実用に足りると思います。
36
+
37
+
38
+
39
+ Javaしかできないので、Javaで実装してみました。
40
+
41
+ 仕切りが〇より多くなる場合は、逆に〇を入れる位置を考える、という考え方をしています。
42
+
43
+ ```java
44
+
45
+ import java.util.*;
46
+
47
+
48
+
49
+ public class Main {
50
+
51
+ public static void main(String[] args) {
52
+
53
+ for (int i = 0; i < 10; i++) {
54
+
55
+ System.out.println(Arrays.toString(randomSplit(10,3)));
56
+
57
+ }
58
+
59
+ }
60
+
61
+
62
+
63
+ private static int[] randomSplit(int n, int p) {
64
+
65
+ int r = p - 1;
66
+
67
+ int total = n + r;
68
+
69
+ boolean wall = total > r * 2;
70
+
71
+ if (!wall) {
72
+
73
+ r = n;
74
+
75
+ }
76
+
77
+ BitSet set = new BitSet(total);
78
+
79
+ while (set.cardinality() < r) {
80
+
81
+ set.set((int)(Math.random() * total));
82
+
83
+ }
84
+
85
+ if (!wall) {
86
+
87
+ set.flip(0, total);
88
+
89
+ }
90
+
91
+
92
+
93
+ int[] result = new int[p];
94
+
95
+ int prev = 0;
96
+
97
+ for (int i = 0; i < r; i++) {
98
+
99
+ int next = set.nextSetBit(prev);
100
+
101
+ result[i] = next - prev;
102
+
103
+ prev = next + 1;
104
+
105
+ }
106
+
107
+ result[r] = total - prev;
108
+
109
+ return result;
110
+
111
+ }
112
+
113
+ }
114
+
115
+ ```
116
+
117
+ 実行結果(10回ループしています)
118
+
119
+ ```
120
+
121
+ [6, 0, 4]
122
+
123
+ [2, 0, 8]
124
+
125
+ [1, 8, 1]
126
+
127
+ [1, 3, 6]
128
+
129
+ [7, 1, 2]
130
+
131
+ [5, 4, 1]
132
+
133
+ [0, 1, 9]
134
+
135
+ [5, 0, 5]
136
+
137
+ [2, 1, 7]
138
+
139
+ [5, 5, 0]
140
+
141
+ ```

2

乱数の範囲を修正

2021/01/06 10:06

投稿

swordone
swordone

スコア20669

test CHANGED
@@ -1,12 +1,16 @@
1
1
  0以上の整数で分配するという前提で回答します。
2
2
 
3
- [重複組み合わせ](https://mathtrain.jp/tyohukuc)の考え方を利用すると、「分配の仕方」は、「仕切りの入れ方」ととらえることができます。
3
+ [重複組み合わせ](https://mathtrain.jp/tyohukuc)の考え方を利用すると、
4
4
 
5
- そこで、「仕切り入れる場所」として、0~(分配す数+1)の乱数を重複しないように(分配る個数-1)個取れば、
5
+ 分配の方」は「仕切り入れ」ととらえことができま
6
6
 
7
- どの分け方も等確率得ら
7
+ そこ、「仕切りを入る場所」として、0~(分配る数+分配する個数-2)の乱数を
8
8
 
9
+ 重複しないように(分配する個数-1)個取れば、どの分け方も等確率で得られます。
10
+
9
- 例えば、例の場合、つまり10を3つに分配する場合、0~11の12個から乱数を2つ取得します。
11
+ 例えば、例の場合、つまり10を3つに分配する場合、10+3-2=11で、
12
+
13
+ 0~11の12個から乱数を2つ取得します。
10
14
 
11
15
  乱数で得られた位置に仕切りを入れることで、分配の仕方が以下のように対応します。
12
16
 
@@ -26,4 +30,6 @@
26
30
 
27
31
  シャッフルするかフィッシャー・イェーツの方法を利用するのが確実になると思いますが、
28
32
 
29
- 分配する数より分配する個数が十分少なければ、逐次乱数を取り出して重複チェックするのでも十分実用に足りると思います。
33
+ 分配する数より分配する個数が十分少なければ、逐次乱数を取り出して重複チェックするのでも
34
+
35
+ 十分実用に足りると思います。

1

仕切り表現をマークダウン

2021/01/06 09:26

投稿

swordone
swordone

スコア20669

test CHANGED
@@ -8,9 +8,19 @@
8
8
 
9
9
  例えば、例の場合、つまり10を3つに分配する場合、0~11の12個から乱数を2つ取得します。
10
10
 
11
- 「3,7」が出〇〇〇|〇〇〇|〇〇〇〇 「3,3,4」分け方に
11
+ 乱数で得らた位置に仕切りを入れることで分配が以下のよう対応します。
12
12
 
13
+ (位置を示す番号は16進表記)
14
+
15
+ ```plain
16
+
17
+ 0 1 2 3 4 5 6 7 8 9 A B
18
+
19
+ 3,7 -> o o o | o o o | o o o o -> 3,3,4
20
+
13
- 9,10」ならば 〇〇〇〇〇〇〇〇〇||〇 「9,0,1」の分け方に対応します。
21
+ 9,10 -> o o o o o o o o o | | o -> 9,0,1
22
+
23
+ ```
14
24
 
15
25
  重複のないようにするには、0~(分配する数+1)の配列などを作って、
16
26