teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

追記

2019/09/11 03:34

投稿

Zuishin
Zuishin

スコア28675

answer CHANGED
@@ -5,4 +5,78 @@
5
5
  次にその配列をシャッフルします。
6
6
  [フィッシャー–イェーツのシャッフル](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%83%E3%82%B7%E3%83%A3%E3%83%BC%E2%80%93%E3%82%A4%E3%82%A7%E3%83%BC%E3%83%84%E3%81%AE%E3%82%B7%E3%83%A3%E3%83%83%E3%83%95%E3%83%AB) を使うといいでしょう。
7
7
 
8
- その配列の先頭 10 個を取り出せば、目的の結果が得られます。
8
+ その配列の先頭 10 個を取り出せば、目的の結果が得られます。
9
+
10
+ #追記
11
+
12
+ ```C#
13
+ using System;
14
+ using System.Collections.Generic;
15
+ using System.Linq;
16
+
17
+ namespace ConsoleApp1
18
+ {
19
+ class Program
20
+ {
21
+ static Random random = new Random();
22
+
23
+ static void Main(string[] args)
24
+ {
25
+ Console.WriteLine(CountDouble(ByShuffle, 100000));
26
+ Console.WriteLine(CountDouble(ByRetry, 100000));
27
+ }
28
+
29
+ static int CountDouble(Func<int[]> func, int count)
30
+ {
31
+ return Enumerable
32
+ .Repeat(0, count)
33
+ .Select(_ => CountGroup(func()).Where(a => a == 2).Count())
34
+ .Sum();
35
+ }
36
+
37
+ static IEnumerable<int> CountGroup(int[] array)
38
+ {
39
+ return array.GroupBy(a => a).Select(a => a.Count());
40
+ }
41
+
42
+ static int[] ByRetry()
43
+ {
44
+ while (true)
45
+ {
46
+ var result = Enumerable
47
+ .Repeat(0, 10)
48
+ .Select(a => random.Next(10))
49
+ .ToArray();
50
+ if (CountGroup(result).Max() < 3)
51
+ {
52
+ return result;
53
+ }
54
+ }
55
+ }
56
+
57
+ static int[] ByShuffle()
58
+ {
59
+ var buffer = new int[20];
60
+ for (int i = 0; i < 20; i++)
61
+ {
62
+ buffer[i] = i / 2;
63
+ }
64
+ for (int i = 19; i >= 1; i--)
65
+ {
66
+ int j = random.Next(20);
67
+ (buffer[i], buffer[j]) = (buffer[j], buffer[i]);
68
+ }
69
+ return buffer.Take(10).ToArray();
70
+ }
71
+ }
72
+ }
73
+ ```
74
+
75
+ 上記コードで検証したところ、10 万回行って同じ数字が 2 個あるものの組数を合計すると、以下のようになりました。
76
+
77
+ ```
78
+ シャッフル: 24 万
79
+ リトライ: 28 万
80
+ ```
81
+
82
+ シャッフルバージョンは同じ数字が含まれる確率がリトライバージョンに比べてやや低いようです。これが問題になるようであれば、リトライしてください。