- 締切済み
簡単なパターン検索のロジック
ちょっとお遊びみたいな感覚で、以下の要件のロジックを作ってといわれたのですが、思いのほか苦戦をしているので、助言頂けますでしょうか。 ・赤/青のボールがあるとします。 ・プログラム実行時に、赤と青のボールの数は変動します。 ・ボールの数は、赤/青両方とも最低1個あります。 ・ボールの数は、赤/青足して、10個以上あります。 ・赤/青のボールを使って、10/11/12個の組み合わせを作っていきます。 ・その際、組み合わせの中に、必ず赤/青が1個以上入っている必要があります。 ・組み合わせを作っていった結果、余らないような組み合わせはどの様なものかを出力してください。 ・尚、その様な組み合わせが存在しない場合はその旨のメッセージを出力してください。 例えば 赤40個、青47個のボールがあった場合、 11個の組み合わせが7つ (赤5個、青6個) 10個の組み合わせが1つ (赤5個、青5個) といった組み合わせを表示する必要があります。 ご助言、よろしくお願いします。
- みんなの回答 (3)
- 専門家の回答
みんなの回答
- nda23
- ベストアンサー率54% (777/1415)
総当り方式でやってみました。ExcelのVBAで組合せを記録しています。 A列:少の個数、B列:多の個数、C列:組の個数 ← 10個組 D列:少の個数、E列:多の個数、F列:組の個数 ← 11個組 G列:少の個数、H列:多の個数、I列:組の個数 ← 12個組 Sub 解析(ByVal 少 As Long, ByVal 多 As Long) Dim 始10 As Long, 始11 As Long, 始12 As Long Dim 限10 As Long, 限11 As Long, 限12 As Long Dim 数10 As Long, 数11 As Long, 数12 As Long Dim 字 As String, 添 As Long Dim 少作 As Long, 多作 As Long Cells.ClearContents For 始10 = 0 To 9 少作 = 少 多作 = 多 限10 = 組10個(少作, 多作, 10, 始10, 少) For 限10 = 限10 To 0 Step -1 For 始11 = 0 To 10 少作 = 少 多作 = 多 限11 = 組10個(少作, 多作, 11, 始11, 少) For 限11 = 限11 To 0 Step -1 For 始12 = 0 To 11 少作 = 少 多作 = 多 限12 = 組10個(少作, 多作, 12, 始12, 少) For 限12 = 限12 To 0 Step -1 少作 = 少 多作 = 多 数10 = 組10個(少作, 多作, 10, 始10, 限10) 数11 = 組10個(少作, 多作, 11, 始11, 限11) 数12 = 組10個(少作, 多作, 12, 始12, 限12) If 少作 = 0 And 多作 = 0 Then 行 = 行 + 1 字 = CStr(行) Cells(行, 1) = 始10 Cells(行, 2) = 10 - 始10 Cells(行, 3) = 数10 Cells(行, 4) = 始11 Cells(行, 5) = 11 - 始11 Cells(行, 6) = 数11 Cells(行, 7) = 始12 Cells(行, 8) = 12 - 始12 Cells(行, 9) = 数12 添 = 9 If 行 > 1 Then For 添 = 添 To 1 Step -1 If Cells(行, 添).Value <> Cells(行 - 1, 添).Value Then Exit For Next End If If 添 = 0 Then Rows(字 & ":" & 字).ClearContents 行 = 行 - 1 End If End If Next Next Next Next Next Next End Sub Function 組10個(少 As Long, 多 As Long, ByVal 全 As Long, ByVal 始 As Long, ByVal 限 As Long) As Long 組10個 = 0 If 始 <= 0 Or 始 > 少 Then Exit Function Dim 要 As Long 要 = 全 - 始 If 要 > 多 Then Exit Function Dim 数 As Long Dim 作 As Long 数 = 少 \ 始 If 数 > 限 Then 数 = 限 For 数 = 数 To 1 Step -1 作 = 数 * 要 If 作 <= 多 Then Exit For Next 少 = 少 - (数 * 始) 多 = 多 - 作 組10個 = 数 End Function
- smcss
- ベストアンサー率63% (7/11)
先の回答、補足と訂正です。 >12*A + 11*B + 10*C = 赤の数 となりうる 自然数 A,B,C この部分は、 3*A + 1*B + 4*C == 赤の数 に訂正します。 また単純に10で割ってしまうのは不十分でした。 たとえば110の場合、10個が11グループとしかなりませんが 11個の10グループもある訳なので、その組み合わせが抜け落ちてしまいます。 別の方法を考え直した方がいいかもしれません。
- smcss
- ベストアンサー率63% (7/11)
すこし考えてみました。 まず、ボールの色は無視してあわせた玉の数を、10/11/12個の組み合わせで分けられるパターンを 考えてみます。 10 / 10+1 / 10+2 と考えてどのグループも最低10個必要であるので、10で割った商がグループ数 になり余りはたかだか1~9までなので、その余りをグループに分配します。 (例) 赤40個、青47個のボールがあった場合 40+47 = 87 87÷10 = 8 余り 7 余り7個を8つのグループに分ける。 7個の分け方は (2,2,2,1) ---------(a) (2,2,1,1,1) -------(b) (2,1,1,1,1,1)------(c) (1,1,1,1,1,1,1)----(d) の4パターンで (a)の場合で分けると (10+2, 10+2, 10+2, 10+1, 10, 10, 10, 10) だから 12個のグループが3、11個のグループが1, 10個のグループが4 (b)の場合、12が2, 11が3, 10が3 (c)の場合、12が1,11が5,10が2 (d)の場合、12が0, 11が7,10が1 次に色に注目して、どちらか一方を考えれば十分なので少ない方の「赤」で考える。 12*A + 11*B + 10*C = 赤の数 となりうる 自然数 A,B,C が存在することが必要十分なので プログラム的にしらみつぶしに調べる。 ----------------------------- (a)の場合を考えると for (A = 1; A<12 ; A++) { for (B = 1; B<11; B++) { for (C = 1; C<10; C++) { if (3*A + 1*B + 4*C == 赤の数) { (A,B,C) の組み合わせをどこかに保持しておく } } } } 赤が必ず1こ、青の必ず1個含まれているので ループが A(1~11)、B(1~10)、C(1~9)の範囲になります 結果 (a)の場合 (A,B,C)の組み合わせがいくつかあったとして 12個のグループは 3 つ 赤 A 個 青 12-A 個 11個のグループは1つ 赤 B 個 青 11-B 10個のグループは4個 赤 C 青 10-C (A,B,C)の組み合わせが存在しなかった場合は、その旨メッセージを出す。 --------------------------------- 以下 (b),(c),(d)も同様に処理する。 しらみつぶしの部分は、もう少し効率的にできそうです。 また全体的にもしらみつぶしな方法なので、数学が得意な人がやればもっとエレガントな方法が見つかると思います。