回答編集履歴
3
文面の微修正とコード添付
answer
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
0以上の整数で分配するという前提で回答します。
|
2
2
|
[重複組み合わせ](https://mathtrain.jp/tyohukuc)の考え方を利用すると、
|
3
3
|
「分配の仕方」は「仕切りの入れ方」ととらえることができます。
|
4
|
-
そこで、「仕切りを入れる場所」として、0
|
4
|
+
そこで、「仕切りを入れる場所」として、0以上(分配する数+分配する個数-1)未満の乱数を
|
5
5
|
重複しないように(分配する個数-1)個取れば、どの分け方も等確率で得られます。
|
6
|
-
例えば、例の場合、つまり10を3つに分配する場合、10+3-
|
6
|
+
例えば、例の場合、つまり10を3つに分配する場合、10+3-1=12なので、
|
7
7
|
0~11の12個から乱数を2つ取得します。
|
8
8
|
乱数で得られた位置に仕切りを入れることで、分配の仕方が以下のように対応します。
|
9
9
|
(位置を示す番号は16進表記)
|
@@ -15,4 +15,57 @@
|
|
15
15
|
重複のないようにするには、0~(分配する数+1)の配列などを作って、
|
16
16
|
シャッフルするかフィッシャー・イェーツの方法を利用するのが確実になると思いますが、
|
17
17
|
分配する数より分配する個数が十分少なければ、逐次乱数を取り出して重複チェックするのでも
|
18
|
-
十分実用に足りると思います。
|
18
|
+
十分実用に足りると思います。
|
19
|
+
|
20
|
+
Javaしかできないので、Javaで実装してみました。
|
21
|
+
仕切りが〇より多くなる場合は、逆に〇を入れる位置を考える、という考え方をしています。
|
22
|
+
```java
|
23
|
+
import java.util.*;
|
24
|
+
|
25
|
+
public class Main {
|
26
|
+
public static void main(String[] args) {
|
27
|
+
for (int i = 0; i < 10; i++) {
|
28
|
+
System.out.println(Arrays.toString(randomSplit(10,3)));
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
private static int[] randomSplit(int n, int p) {
|
33
|
+
int r = p - 1;
|
34
|
+
int total = n + r;
|
35
|
+
boolean wall = total > r * 2;
|
36
|
+
if (!wall) {
|
37
|
+
r = n;
|
38
|
+
}
|
39
|
+
BitSet set = new BitSet(total);
|
40
|
+
while (set.cardinality() < r) {
|
41
|
+
set.set((int)(Math.random() * total));
|
42
|
+
}
|
43
|
+
if (!wall) {
|
44
|
+
set.flip(0, total);
|
45
|
+
}
|
46
|
+
|
47
|
+
int[] result = new int[p];
|
48
|
+
int prev = 0;
|
49
|
+
for (int i = 0; i < r; i++) {
|
50
|
+
int next = set.nextSetBit(prev);
|
51
|
+
result[i] = next - prev;
|
52
|
+
prev = next + 1;
|
53
|
+
}
|
54
|
+
result[r] = total - prev;
|
55
|
+
return result;
|
56
|
+
}
|
57
|
+
}
|
58
|
+
```
|
59
|
+
実行結果(10回ループしています)
|
60
|
+
```
|
61
|
+
[6, 0, 4]
|
62
|
+
[2, 0, 8]
|
63
|
+
[1, 8, 1]
|
64
|
+
[1, 3, 6]
|
65
|
+
[7, 1, 2]
|
66
|
+
[5, 4, 1]
|
67
|
+
[0, 1, 9]
|
68
|
+
[5, 0, 5]
|
69
|
+
[2, 1, 7]
|
70
|
+
[5, 5, 0]
|
71
|
+
```
|
2
乱数の範囲を修正
answer
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
0以上の整数で分配するという前提で回答します。
|
2
|
-
[重複組み合わせ](https://mathtrain.jp/tyohukuc)の考え方を利用すると、
|
2
|
+
[重複組み合わせ](https://mathtrain.jp/tyohukuc)の考え方を利用すると、
|
3
|
+
「分配の仕方」は「仕切りの入れ方」ととらえることができます。
|
3
|
-
そこで、「仕切りを入れる場所」として、0~(分配する数+
|
4
|
+
そこで、「仕切りを入れる場所」として、0~(分配する数+分配する個数-2)の乱数を
|
4
|
-
どの分け方も等確率で得られます。
|
5
|
+
重複しないように(分配する個数-1)個取れば、どの分け方も等確率で得られます。
|
5
|
-
例えば、例の場合、つまり10を3つに分配する場合、
|
6
|
+
例えば、例の場合、つまり10を3つに分配する場合、10+3-2=11なので、
|
7
|
+
0~11の12個から乱数を2つ取得します。
|
6
8
|
乱数で得られた位置に仕切りを入れることで、分配の仕方が以下のように対応します。
|
7
9
|
(位置を示す番号は16進表記)
|
8
10
|
```plain
|
@@ -12,4 +14,5 @@
|
|
12
14
|
```
|
13
15
|
重複のないようにするには、0~(分配する数+1)の配列などを作って、
|
14
16
|
シャッフルするかフィッシャー・イェーツの方法を利用するのが確実になると思いますが、
|
15
|
-
分配する数より分配する個数が十分少なければ、逐次乱数を取り出して重複チェックするのでも
|
17
|
+
分配する数より分配する個数が十分少なければ、逐次乱数を取り出して重複チェックするのでも
|
18
|
+
十分実用に足りると思います。
|
1
仕切り表現をマークダウン
answer
CHANGED
@@ -3,8 +3,13 @@
|
|
3
3
|
そこで、「仕切りを入れる場所」として、0~(分配する数+1)の乱数を重複しないように(分配する個数-1)個取れば、
|
4
4
|
どの分け方も等確率で得られます。
|
5
5
|
例えば、例の場合、つまり10を3つに分配する場合、0~11の12個から乱数を2つ取得します。
|
6
|
-
「3,7」が出れば、〇〇〇|〇〇〇|〇〇〇〇 「3,3,4」の分け方に、
|
7
|
-
|
6
|
+
乱数で得られた位置に仕切りを入れることで、分配の仕方が以下のように対応します。
|
7
|
+
(位置を示す番号は16進表記)
|
8
|
+
```plain
|
9
|
+
0 1 2 3 4 5 6 7 8 9 A B
|
10
|
+
3,7 -> o o o | o o o | o o o o -> 3,3,4
|
11
|
+
9,10 -> o o o o o o o o o | | o -> 9,0,1
|
12
|
+
```
|
8
13
|
重複のないようにするには、0~(分配する数+1)の配列などを作って、
|
9
14
|
シャッフルするかフィッシャー・イェーツの方法を利用するのが確実になると思いますが、
|
10
15
|
分配する数より分配する個数が十分少なければ、逐次乱数を取り出して重複チェックするのでも十分実用に足りると思います。
|