回答編集履歴
3
文面の微修正とコード添付
test
CHANGED
@@ -4,11 +4,11 @@
|
|
4
4
|
|
5
5
|
「分配の仕方」は「仕切りの入れ方」ととらえることができます。
|
6
6
|
|
7
|
-
そこで、「仕切りを入れる場所」として、0
|
7
|
+
そこで、「仕切りを入れる場所」として、0以上(分配する数+分配する個数-1)未満の乱数を
|
8
8
|
|
9
9
|
重複しないように(分配する個数-1)個取れば、どの分け方も等確率で得られます。
|
10
10
|
|
11
|
-
例えば、例の場合、つまり10を3つに分配する場合、10+3-
|
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
乱数の範囲を修正
test
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
0以上の整数で分配するという前提で回答します。
|
2
2
|
|
3
|
-
[重複組み合わせ](https://mathtrain.jp/tyohukuc)の考え方を利用すると、
|
3
|
+
[重複組み合わせ](https://mathtrain.jp/tyohukuc)の考え方を利用すると、
|
4
4
|
|
5
|
-
|
5
|
+
「分配の仕方」は「仕切りの入れ方」ととらえることができます。
|
6
6
|
|
7
|
-
|
7
|
+
そこで、「仕切りを入れる場所」として、0~(分配する数+分配する個数-2)の乱数を
|
8
8
|
|
9
|
+
重複しないように(分配する個数-1)個取れば、どの分け方も等確率で得られます。
|
10
|
+
|
9
|
-
例えば、例の場合、つまり10を3つに分配する場合、0
|
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
仕切り表現をマークダウン
test
CHANGED
@@ -8,9 +8,19 @@
|
|
8
8
|
|
9
9
|
例えば、例の場合、つまり10を3つに分配する場合、0~11の12個から乱数を2つ取得します。
|
10
10
|
|
11
|
-
|
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
|
-
|
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
|
|