tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトル組み合わせ合計検索 つづき
記事No12125
投稿日: 2023/08/11(Fri) 06:34
投稿者たけし
お世話になります。

組み合わせ合計検索
サンプル 23/02/12 10:52 No.12102 についてです。




Dim 値一覧1 As Integer() = {60, 57, 54, 45, 42, 500, 1000, 60, 25, 57}

↑こちらの部分を

以下のように代入しまして


       Dim sDATA() As Integer  
        ReDim sDATA(100)

        Dim cnt As Integer
        cnt = 0

        For i As Integer = 0 To DataGridView1.Rows.Count - 1
          

            sDATA(cnt) = Me.DataGridView1(1, i).Value
            cnt = cnt + 1

            If Me.DataGridView1(6, i).Value <> "" Then
                Data2 = Me.DataGridView1(6, i).Value

                For ii As Integer = 0 To Data2 - 2

                    sDATA(cnt) = Me.DataGridView1(1, i).Value
                    cnt = cnt + 1

                Next ii

            End If

        Next i




探索(590, sDATA) を実行すると

↓こちらでエラーでます。

If values.Any(Function(v) v <= 0) Then Throw New ArgumentOutOfRangeException("values", "自然数が必要です。")


配列の宣言方法に問題あるのでしょうか?

よろしくお願いします。

[ツリー表示へ]
タイトルRe: 組み合わせ合計検索 つづき
記事No12127
投稿日: 2023/08/14(Mon) 23:36
投稿者魔界の仮面弁士
> 組み合わせ合計検索
> サンプル 23/02/12 10:52 No.12102 についてです。
これですね。
http://hanatyan.sakura.ne.jp/vbnetbbs/wforum.cgi?no=12102&reno=12091&oya=12091&mode=msgview&page=0

今でも VB2010 (.NET Framework 4) のままなのでしょうか?



> ↓こちらでエラーでます。
>  If values.Any(Function(v) v <= 0) Then Throw New ArgumentOutOfRangeException("values", "自然数が必要です。")

ということは、values 配列の中に「0 またはそれ以下の値」が混入していたということに他なりません。
渡した配列の中身が、すべて 1 以上の自然数であることを確認していますか?

以前の質問では、
>> 値はすべて自然数ですか? それとも負の整数なども含まれますか?
> 自然数のみです。
というやりとりがあったはずです。今回の要件も同じと考えて良いのでしょうか?
「0」や「-1」は自然数ではありませんので、負数が混入した時は範囲外エラーとして扱っているわけです。


> 以下のように代入しまして
唐突に DataGridView が出てきましたが、何行何列の構成になっていて、
どういうデータが入っているのか分からないので、第三者が検証しにくいです。

コードの意図も不明瞭な上に、どのようなデータが渡されているのかも分からない状況ゆえ、
間違いを指摘する以前の問題として、そもそも何がやりたいのかさえ把握できないです。



> Dim sDATA() As Integer  
> ReDim sDATA(100)
なぜこんな面倒な書き方を…?
VBA ではあるまいし、要素数が 101 個の配列を確保したいだけならば、
素直に「Dim sDATA(100) As Integer」だけで良いような。

というか 101 個固定で良いのですか?
そしてその 101 個の値は、すべてが(0 ではなく)自然数のみの一覧になっていることを保証できていますか?

個数が未定ならば配列なんて使わずに、Dim sDATA As New List(Of Integer)() あたりにしておき、
 sDATA(番号) = 新しい値
の代わりに
 sDATA.Add( 新しい値 )
の形で登録するようにすれば、要素数を可変にできます。これなら、変数 cnt の管理も不要になるかと。


> 探索(590, sDATA) を実行すると
ひとまず、ここまでに書かれていた DataGridView 云々の部分は、
質問の本題に対しては、何の意味も無いようです。


エラーの理由を特定したいのであれば、エラーに至ったこの時点における
変数 sDATA の中身がどうなっていたのかを、具体的に示してもらった方が手っ取り早いです。

(1) DataGridView の情報に問題があって、sDATA の中身が想定外になっているのか?
(2) DataGridView のデータは正しいけれど、それを sDATA に詰める処理に手順ミスがあるのか?
(3) sDATA の中身は正しいけれど、「探索」処理が期待動作してくれていないのか?

そういった点を調査できるのは、実際にデータを保有している貴方自身だけです。



結局のところ、最初に実施すべき作業は「調査」です。
sDATA の中身が想定と違っていたからエラーになったのか、それとも、
sDATA の中身は想定通りだったけれど、探索処理に問題があってエラーになったのかを調べましょう。

プログラムを修正するのは、そうした調査による現状把握が終わってからの話です。
原因を突き止めてからでなければ、修正のしようがありませんからね。


=== 以下蛇足 ===

> Dim cnt As Integer
> cnt = 0
2 行に分ける意味が無いので、「Dim cnt = 0」で十分かと。


> For i As Integer = 0 To DataGridView1.Rows.Count - 1
>  sDATA(cnt) = Me.DataGridView1(1, i).Value
このコードを見る限り、「Option Strict On」設定ではないようですね。

左辺の sDATA(cnt) は Integer 型で、右辺の Value プロパティは Object 型です。
代入式の左右で、データ型が一致していません。


>  If Me.DataGridView1(6, i).Value <> "" Then
>   Data2 = Me.DataGridView1(6, i).Value
今度は、比較式の左辺が Object 型で、右辺が String 型な点に違和感があります。

データ型を常に意識しましょう。
また、変数 Data2 が唐突に現れましたが、これがどんな型の変数なのか示されていません。

たとえば Integer 型への変換を必要としているなら、Integer.TryParse メソッドの利用を検討してください。
これならば、入力値を整数型に変換できるかどうかの検査も一緒に行うことができます。
https://hiros-dot.net/VBNET2005/String/String14.htm
第一引数に文字列、第二引数に Integer 型変数を渡します。
戻り値は、変換成功なら True、変換失敗なら False となります。


>  For ii As Integer = 0 To Data2 - 2
>   sDATA(cnt) = Me.DataGridView1(1, i).Value
>   cnt = cnt + 1
>  Next ii
ここも、もう少し整理できそう。
ループ内で変数 i は変化しないのに、毎回、セルを参照し続けるのはあまり効率が良くないです。

[ツリー表示へ]
タイトルRe^2: 組み合わせ合計検索 つづき
記事No12128
投稿日: 2023/08/16(Wed) 15:16
投稿者たけし
お世話になります。

> 今でも VB2010 (.NET Framework 4) のままなのでしょうか?
はい。

> > ↓こちらでエラーでます。
> >  If values.Any(Function(v) v <= 0) Then Throw New ArgumentOutOfRangeException("values", "自然数が必要です。")

Dim sDATA(100) As Integer
に対して  {36, 40, 45, 51} 4つ分しか代入しなかったので
エラーでているようでした。

以下のように変更したところ正常終了できるようになりました。
Dim sDATA(100) As Integer → Dim sDATA(DataGridView1.Rows.Count - 1) As Integer


> > 以下のように代入しまして
> 唐突に DataGridView が出てきましたが、何行何列の構成になっていて、
すみませんでした。DataGridViewの値は以下でテストしていました。
{60, 57, 54, 45, 42, 500, 1000, 60, 25, 57}



> === 以下蛇足 ===
>
> > Dim cnt As Integer
> > cnt = 0
> 2 行に分ける意味が無いので、「Dim cnt = 0」で十分かと。
>
>
> > For i As Integer = 0 To DataGridView1.Rows.Count - 1
> >  sDATA(cnt) = Me.DataGridView1(1, i).Value
> このコードを見る限り、「Option Strict On」設定ではないようですね。
>
> 左辺の sDATA(cnt) は Integer 型で、右辺の Value プロパティは Object 型です。
> 代入式の左右で、データ型が一致していません。
>
>
> >  If Me.DataGridView1(6, i).Value <> "" Then
> >   Data2 = Me.DataGridView1(6, i).Value
> 今度は、比較式の左辺が Object 型で、右辺が String 型な点に違和感があります。
>
> データ型を常に意識しましょう。
> また、変数 Data2 が唐突に現れましたが、これがどんな型の変数なのか示されていません。
>
> たとえば Integer 型への変換を必要としているなら、Integer.TryParse メソッドの利用を検討してください。
> これならば、入力値を整数型に変換できるかどうかの検査も一緒に行うことができます。
> https://hiros-dot.net/VBNET2005/String/String14.htm
> 第一引数に文字列、第二引数に Integer 型変数を渡します。
> 戻り値は、変換成功なら True、変換失敗なら False となります。
>
>
> >  For ii As Integer = 0 To Data2 - 2
> >   sDATA(cnt) = Me.DataGridView1(1, i).Value
> >   cnt = cnt + 1
> >  Next ii
> ここも、もう少し整理できそう。
> ループ内で変数 i は変化しないのに、毎回、セルを参照し続けるのはあまり効率が良くないです。

参考になりました。
ありがとうございます。




続いて以下の値でテストしてみました。

Dim 値一覧3 As Integer() = {36, 40, 45, 51, 55, 65, 69, 76, 82, 98, 106, 108, 115, 116, 118, 119, 123, 129, 133, 139, 148, 159, 163, 165, 184, 186}

探索(1230, 値一覧3)


  For 設定値 = 設定値 To 設定値 - ★ Step -1
            結果 = FindCombination(設定値, 寸法一覧)
            If 結果.Length > 0 Then Exit For
  Next


★の値を20に設定すると  Console.WriteLine("抽出できませんでした。") となり
★の値を50に設定すると  Console.WriteLine("合計値:{0} 詳細値:{1}", 結果.Sum(), String.Join(", ", 結果.Select(Function(寸法) CStr(寸法)))) でてきます。



★の値を20にした場合でも
例えば 186+184+165+163+159+148+106+115 = 1226なので
正常終了させたいです。
  
何か良い方法ありましたでしょうか。


[ツリー表示へ]
タイトルRe^3: 組み合わせ合計検索 つづき
記事No12129
投稿日: 2023/08/16(Wed) 16:27
投稿者魔界の仮面弁士
> Dim 値一覧3 As Integer() = {36, 40, 45, 51, 55, 65, 69, 76, 82, 98, 106, 108, 115, 116, 118, 119, 123, 129, 133, 139, 148, 159, 163, 165, 184, 186}
> 探索(1230, 値一覧3)
>
> For 設定値 = 設定値 To 設定値 - ★ Step -1
>
> ★の値を20に設定すると  Console.WriteLine("抽出できませんでした。") となり
> ★の値を50に設定すると  Console.WriteLine("合計値:{0} 詳細値:{1}", 結果.Sum(), String.Join(", ", 結果.Select(Function(寸法) CStr(寸法)))) でてきます。

No.12102 のロジックなんですよね?

手元の環境だと近似値ではなく
設定値:1230 合計値:1230 詳細値:36, 40, 45, 51, 55, 65, 69, 76, 82, 98, 106, 108, 115, 119, 165
というそのものズバリの結果が得られたので、★の値は無関係のはずなのですが。



> ★の値を20にした場合でも
> 例えば 186+184+165+163+159+148+106+115 = 1226なので
> 正常終了させたいです。

まぁ、それも回答の一つではあるのですが、
> > > サンプル 23/02/12 10:52 No.12102 についてです。
のロジックでは
 36+40+45+51+55+65+69+76+82+98+106+108+118+129+148 = 1226
の方が検出されると思います。

ちなみに、その「値一覧3」を対象にする場合の組み合わせは
 合計が 1226 になる組み合わせは 72,832 通り
 合計が 1230 になる組み合わせは 73,221 通り
になると思います。(a+b と b+a を同じ組み合わせとして扱った場合)


ひとまず、★の値を 0 にして、1220〜1250 の範囲で試してみましたが、
No.12102 のコードで、下記の組み合わせを検出できています。
 For n = 1220 To 1250
  探索(n, 値一覧3)
 Next

 1220 = 36+40+45+51+55+65+69+76+82+98+106+108+118+123+148
 1221 = 36+40+45+51+55+65+69+76+82+98+106+108+115+116+159
 1222 = 36+40+45+51+55+65+69+76+82+98+106+108+119+133+139
 1223 = 36+40+45+51+55+65+69+76+82+98+106+108+115+118+159
 1224 = 36+40+45+51+55+65+69+76+82+98+106+108+115+119+159
 1225 = 36+40+45+51+55+65+69+76+82+98+106+108+115+116+163
 1226 = 36+40+45+51+55+65+69+76+82+98+106+108+118+129+148
 1227 = 36+40+45+51+55+65+69+76+82+98+106+108+115+116+165
 1228 = 36+40+45+51+55+65+69+76+82+98+106+108+115+119+163
 1229 = 36+40+45+51+55+65+69+76+82+98+106+108+115+118+165
 1230 = 36+40+45+51+55+65+69+76+82+98+106+108+115+119+165
 1231 = 36+40+45+51+55+65+69+76+82+98+106+108+116+119+165
 1232 = 36+40+45+51+55+65+69+76+82+98+106+108+115+123+163
 1233 = 36+40+45+51+55+65+69+76+82+98+106+108+115+139+148
 1234 = 36+40+45+51+55+65+69+76+82+98+106+108+115+123+165
 1235 = 36+40+45+51+55+65+69+76+82+98+106+108+116+123+165
 1236 = 36+40+45+51+55+65+69+76+82+98+106+108+118+139+148
 1237 = 36+40+45+51+55+65+69+76+82+98+106+108+118+123+165
 1238 = 36+40+45+51+55+65+69+76+82+98+106+108+115+129+163
 1239 = 36+40+45+51+55+65+69+76+82+98+106+108+116+129+163
 1240 = 36+40+45+51+55+65+69+76+82+98+106+108+115+129+165
 1241 = 36+40+45+51+55+65+69+76+82+98+106+108+116+129+165
 1242 = 36+40+45+51+55+65+69+76+82+98+106+108+115+133+163
 1243 = 36+40+45+51+55+65+69+76+82+98+106+108+116+133+163
 1244 = 36+40+45+51+55+65+69+76+82+98+106+108+115+133+165
 1245 = 36+40+45+51+55+65+69+76+82+98+106+108+116+133+165
 1246 = 36+40+45+51+55+65+69+76+82+98+106+108+115+116+184
 1247 = 36+40+45+51+55+65+69+76+82+98+106+108+118+133+165
 1248 = 36+40+45+51+55+65+69+76+82+98+106+108+115+116+186
 1249 = 36+40+45+51+55+65+69+76+82+98+106+108+115+119+184
 1250 = 36+40+45+51+55+65+69+76+82+98+106+108+115+118+186

[ツリー表示へ]
タイトルRe^4: 組み合わせ合計検索 つづき
記事No12131
投稿日: 2023/08/17(Thu) 10:36
投稿者たけし

お世話になります。


'No12097 の設問
Dim 値一覧1 As Integer() = {60, 57, 54, 45, 42, 500, 1000, 60, 25, 57}

'No.12091 の設問
Dim 値一覧2 As Integer() = {5988, 2994, 1245, 3296, 19777, 1497, 14823, 13177, 37885, 5988, 6290, 6038, 22653, 28474, 29564, 26871, 23844, 4366, 4101, 14116, 7037, 17500, 24062, 23644, 17717, 25162, 9461, 19788, 29762, 25099, 28935, 1011, 4655, 22234, 9589, 30377, 10081, 2887, 24336, 3517, 16020, 6494, 16745, 24100, 28340, 24825, 13382, 6801, 19893, 28700}

Dim 値一覧3 As Integer() = {36, 40, 45, 51, 55, 65, 69, 76, 82, 98, 106, 108, 115, 116, 118, 119, 123, 129, 133, 139, 148, 159, 163, 165, 184, 186}

        


'『設定値:590 合計値:587 詳細値:42, 45, 500』
探索(590, 値一覧1)

'『設定値:586 合計値:585 詳細値:25, 60, 500』
探索(586, 値一覧1)

'『設定値:88792 合計値:88792 詳細値:1011, 1245, 1497, 2887, 2994, 3296, 3517, 4101, 4366, 4655, 6290, 6494, 14116, 14823, 17500』
探索(88792, 値一覧2)

探索(1230, 値一覧3)



↑実行しますと 以下のようになります。

設定値:590 抽出できませんでした。
設定値:586 抽出できませんでした。
設定値:88792 抽出できませんでした。
設定値:1230 抽出できませんでした。

このような結果になりますか?



何か違いがあるのかと思い、
No.12102 のロジックをもう一度、現在のフォームにあるプログラムへ貼り付けると
iの部分でエラーでるので以下のように宣言していました。

For i = index To maxIndex


      '設定値を超えるものは除外した上で、[値]の昇順に並べる
        Dim ordered As Integer() = (From v In values Where v <= targetValue Order By v).ToArray()
        Dim i As Integer = 0

何か環境に違いがあるのでしょうか?

[ツリー表示へ]
タイトルRe^5: 組み合わせ合計検索 つづき
記事No12132
投稿日: 2023/08/17(Thu) 11:10
投稿者魔界の仮面弁士
> お世話になります。
> ↑実行しますと 以下のようになります。

比較すると、追加されているのは、
 Dim 値一覧3 As Integer() = 〜
 探索(1230, 値一覧3)
の 2 か所だけですね。


> このような結果になりますか?
なりません。
手元の VS2010 で新規プロジェクトを用意し、そのまま漏らさず貼りつけてみると
 設定値:590 合計値:587 詳細値:42, 45, 500
 設定値:586 合計値:585 詳細値:25, 60, 500
 設定値:88792 合計値:88792 詳細値:1011, 1245, 1497, 2887, 2994, 3296, 3517, 4101, 4366, 4655, 6290, 6494, 14116, 14823, 17500
 設定値:1230 合計値:1230 詳細値:36, 40, 45, 51, 55, 65, 69, 76, 82, 98, 106, 108, 115, 119, 165
という結果が出力されます。


> No.12102 のロジックをもう一度、現在のフォームにあるプログラムへ貼り付けると
> iの部分でエラーでるので以下のように宣言していました。
なんというエラーが出ているのですか?


>  For i = index To maxIndex
>       '設定値を超えるものは除外した上で、[値]の昇順に並べる
>         Dim ordered As Integer() = (From v In values Where v <= targetValue Order By v).ToArray()
>         Dim i As Integer = 0

いや、なんのためにそんな“破壊工作”を…!?

ループ前にあったフィルタリング(と並び替え)を、わざわざ
ループ内で毎回やりなおす形に書き換えている時点で、まず意味が分からないですし、
何より今のそのコードでは、「For i = index To …」と「Dim i As Integer = …」とで
変数 i が重複して宣言されてしまっているではないですか。
アルゴリズム以前の問題として、文法エラーになってしまいますので、
そもそも実行すらできないはず。


それに、そのループ終端となっている「To maxIndex」の値を求める処理は、
本来の元ソースでは For 文の直前に書かれた
 '探索処理
  Dim maxIndex = ordered.GetUpperBound(0)
という処理であったはずです。(値リストから、余剰データを除去した後の最大Indexを取得)

それなのに、その変数 ordered の宣言さえも、ループの前では無く、
ループ内で「Dim ordered As Integer() = ……」と書かれているわけですよね。
そうなると、maxIndex の算出時点で、変数未定義エラーになってしまうはず。
出鱈目にも程がありすぎて草枯れそう。

いったいどんなコードを書いているのでしょう? (^_^;

[ツリー表示へ]
タイトルRe^6: 組み合わせ合計検索 つづき
記事No12133
投稿日: 2023/08/17(Thu) 11:26
投稿者たけし
お世話になります。

> > No.12102 のロジックをもう一度、現在のフォームにあるプログラムへ貼り付けると
> > iの部分でエラーでるので以下のように宣言していました。
> なんというエラーが出ているのですか?


error BC30451: 'i' は宣言されていません。アクセスできない保護レベルになっています。

何か設定などに違いあるのでしょううか?

[ツリー表示へ]
タイトルRe^7: 組み合わせ合計検索 つづき
記事No12134
投稿日: 2023/08/17(Thu) 11:49
投稿者魔界の仮面弁士
>  error BC30451: 'i' は宣言されていません。アクセスできない保護レベルになっています。
> 何か設定などに違いあるのでしょううか?

プロジェクトのプロパティで、[コンパイル]タブを開いたときに、
コンパイル オプションで「Option Infer」を On から Off に変更していませんか?

そのような指定がされていないのであれば、No.12102 の元コードを
一字一句違わず貼りつけただけで動くはずです。



改めて、For ループのカウンター変数についておさらいしてみましょう。


VB.NET 2002 および、VB6 や VBA においては
 Dim i As Integer
 For i = 0 To 10
 Next
のように、ループ変数は For 文よりも外側で宣言せねばなりませんでした。


それが VB.NET 2003 では、
 For i As Integer = 0 To 10
 Next
と書くことで、C# などと同様に「For ループの定義と同時に変数宣言」できるようになりました。
また、この書き方で書かれた変数は For の外では使用できない局所変数となるため、
変数のスコープを狭めてくれる効果も得られます。



さらに VB2008 においては、「型推論」の仕組みが追加されたことで、上記の記述を
 For i = 0 To 10
 Next
と、As 句を省略できるようになりました。(VB.NET 2003 と違い、直前に Dim も不要)
この場合、代入式の右辺にある「0」が Integr 値であることから、
コンパイル時には、変数 i が As Integer として扱われるようになっています。
 For i = 0L と書けば As Long 相当

ただし 2008 以降であっても、「Option Infer Off」モードでコンパイルされた場合には、
型推論が使われなくなるため、As 句無しのままでは変数の「宣言」とみなされません。この場合は
>  error BC30451: 'i' は宣言されていません。アクセスできない保護レベルになっています。
というエラーが生じることになってしまいます。



…しかし、仮に Option Infer Off などであったとしても、
 For i = index To maxIndex
      Dim i As Integer = 0
 Next

 For i = index To maxIndex
 Next
  Dim i As Integer = 0
といったコードは文法的に許可されないはずです。
そのため、やはり No.12131 のコードには違和感しかないです…。

[ツリー表示へ]
タイトルRe^8: 組み合わせ合計検索 つづき
記事No12135
投稿日: 2023/08/18(Fri) 22:25
投稿者たけし
お世話になります。

>そのような指定がされていないのであれば、No.12102 の元コードを
>一字一句違わず貼りつけただけで動くはずです。
きちんと動きました。


No.12102 の元コードを理解しようと見ていたのですが
私にとってハードルがとても高いようです。。


以下は
No.12102 のコードをどのように変更すれば確認できますでしょうか?





No.12102 のコードで、下記の組み合わせを検出できています。
 For n = 1220 To 1250
  探索(n, 値一覧3)
 Next

 1220 = 36+40+45+51+55+65+69+76+82+98+106+108+118+123+148
 1221 = 36+40+45+51+55+65+69+76+82+98+106+108+115+116+159
 1222 = 36+40+45+51+55+65+69+76+82+98+106+108+119+133+139
 1223 = 36+40+45+51+55+65+69+76+82+98+106+108+115+118+159
 1224 = 36+40+45+51+55+65+69+76+82+98+106+108+115+119+159
 1225 = 36+40+45+51+55+65+69+76+82+98+106+108+115+116+163
 1226 = 36+40+45+51+55+65+69+76+82+98+106+108+118+129+148
 1227 = 36+40+45+51+55+65+69+76+82+98+106+108+115+116+165
 1228 = 36+40+45+51+55+65+69+76+82+98+106+108+115+119+163
 1229 = 36+40+45+51+55+65+69+76+82+98+106+108+115+118+165
 1230 = 36+40+45+51+55+65+69+76+82+98+106+108+115+119+165
 1231 = 36+40+45+51+55+65+69+76+82+98+106+108+116+119+165
 1232 = 36+40+45+51+55+65+69+76+82+98+106+108+115+123+163
 1233 = 36+40+45+51+55+65+69+76+82+98+106+108+115+139+148
 1234 = 36+40+45+51+55+65+69+76+82+98+106+108+115+123+165
 1235 = 36+40+45+51+55+65+69+76+82+98+106+108+116+123+165
 1236 = 36+40+45+51+55+65+69+76+82+98+106+108+118+139+148
 1237 = 36+40+45+51+55+65+69+76+82+98+106+108+118+123+165
 1238 = 36+40+45+51+55+65+69+76+82+98+106+108+115+129+163
 1239 = 36+40+45+51+55+65+69+76+82+98+106+108+116+129+163
 1240 = 36+40+45+51+55+65+69+76+82+98+106+108+115+129+165
 1241 = 36+40+45+51+55+65+69+76+82+98+106+108+116+129+165
 1242 = 36+40+45+51+55+65+69+76+82+98+106+108+115+133+163
 1243 = 36+40+45+51+55+65+69+76+82+98+106+108+116+133+163
 1244 = 36+40+45+51+55+65+69+76+82+98+106+108+115+133+165
 1245 = 36+40+45+51+55+65+69+76+82+98+106+108+116+133+165
 1246 = 36+40+45+51+55+65+69+76+82+98+106+108+115+116+184
 1247 = 36+40+45+51+55+65+69+76+82+98+106+108+118+133+165
 1248 = 36+40+45+51+55+65+69+76+82+98+106+108+115+116+186
 1249 = 36+40+45+51+55+65+69+76+82+98+106+108+115+119+184
 1250 = 36+40+45+51+55+65+69+76+82+98+106+108+115+118+186

[ツリー表示へ]
タイトルRe^9: 組み合わせ合計検索 つづき
記事No12136
投稿日: 2023/08/19(Sat) 18:57
投稿者魔界の仮面弁士
No.12102 のコードでは、近似値設定 (No.12128 でいうところの★値) が 20 なので、
n と合致する値が無い場合、n-1, n-2, n-3, ……, n-20 に合致する組み合わせを捜索するものですね。


> 以下は
> No.12102 のコードをどのように変更すれば確認できますでしょうか?

Sub Main() の中身を書き換えるだけで確認できますよ。

 Dim 値一覧3 As Integer() = {36, 40, 45, 51, 55, 65, 69, 76, 82, 98, 106, 108, 115, 116, 118, 119, 123, 129, 133, 139, 148, 159, 163, 165, 184, 186}
 For n = 1220 To 1250
  探索(n, 値一覧3)
 Next



No.12102 のロジックでは、
 探索(7, New Integer() {1, 3, 5})
に対しては、
 『設定値:7 合計値:6 詳細値:1, 5』
という結果が得られます。

この出力の意味とは、
 「n の値として 7 が設定された」
 「合計が 7 になる組み合わせは見つからなかったが、合計 6 になる組み合わせは発見できた」
 「その組み合わせとは 1 と 5 である」
です。


これが探索 (1220, 値一覧3) になった場合は、
 『設定値:1220 合計値:1220 詳細値:36, 40, 45, 51, 55, 65, 69, 76, 82, 98, 106, 108, 118, 123, 148』
という結果が取得されていますよね。つまり、
 「n の値として 1220 が設定された」
 「合計が 1220 になる組み合わせが見つかった」
 「その組み合わせとは 36, 40, 45, 51, 55, 65, 69, 76, 82, 98, 106, 108, 118, 123, 148 である」
という意味を持っています。

それを簡略化するために、先の No.12129 においては
>> 1220 = 36+40+45+51+55+65+69+76+82+98+106+108+118+123+148
という表現に書き換えたに過ぎません。


もし、出力結果を直接、上記の足し算表記へ書き換えたいという話であれば
 Console.WriteLine("{0} = {1}", 結果.Sum(), String.Join("+", 結果.Select(Function(寸法) CStr(寸法))))
にすれば OK です。


ちなみに No.12129 において
>> 「値一覧3」を対象にする場合の組み合わせは
>>  合計が 1226 になる組み合わせは 72,832 通り
>>  合計が 1230 になる組み合わせは 73,221 通り
という投稿をしておりますが、こうした組み合わせ数は、No.12104 あるいは No.12105 にて調べられます。

たとえば、『反復探索(1226, 1226, 値一覧3)』とすれば、合計 1226 になる組み合わせを延々と捜索し、
その最後に「総計 72832 件の組み合わせを抽出しました。」という結果を表示するようになっています。


> No.12102 の元コードを理解しようと見ていたのですが
> 私にとってハードルがとても高いようです。。

やっぱり、他人の書いたコードを読むのは難しいですよね……!

必要であれば説明しますが、不明点というのが「VB の文法段階で理解できていない」という事なのか、
それとも「文法は分かるけれど、コードの意味というか探索ロジックが理解できない」という話なのかで
回答も変わってきてしまいます。もしも可能であれば「どこが分からないのか」を説明いただけると
追加解説を加えやすいです。

[ツリー表示へ]
タイトルRe^10: 組み合わせ合計検索 つづき
記事No12137
投稿日: 2023/08/29(Tue) 21:15
投稿者たけし
お世話になります。

結果が以下のように詳細値が15個あります。
これを10個以下で詳細値を求めたいと思っています。

『設定値:1230 詳細値:36, 40, 45, 51, 55, 65, 69, 76, 82, 98, 106, 108, 115, 119, 165』


---------------------------------------------------------------------------------------------------


Dim 値一覧3 As Integer() = {36, 40, 45, 51, 55, 65, 69, 76, 82, 98, 106, 108, 115, 116, 118, 119, 123, 129, 133, 139, 148, 159, 163, 165, 184, 186}

探索(1230, 値一覧3)

---------------------------------------------------------------------------------------------------
Public Sub 探索(ByVal 設定値 As Integer, ByVal 寸法一覧 As Integer(), ByVal kyoyouti As Integer)

        'Console.Write("設定値:{0} ", 設定値)
        Dim 結果 As Integer() = {}

        For 設定値 = 設定値 To 設定値 - 20 Step -1
            結果 = FindCombination(設定値, 寸法一覧)

            If 結果.Length > 0 Then Exit For

        Next

        If 結果.Length = 0 Then
            'Console.WriteLine("抽出できませんでした。")
            MsgBox("抽出できませんでした。")
        Else
            'Console.WriteLine("合計値:{0} 詳細値:{1}", 結果.Sum(), String.Join(", ", 結果.Select(Function(寸法) CStr(寸法))))
         ★   MsgBox("合計値:" & 結果.Sum() & " 詳細値:" & String.Join(", ", 結果.Select(Function(寸法) CStr(寸法))))
        End If

    End Sub

-------------------------------------------------------------------

以下のように変更した場合
msgbox の値は以下のようになります。


一回目:8
二回目:15
三回目(★):『設定値:1230 詳細値:36, 40, 45, 51, 55, 65, 69, 76, 82, 98, 106, 108, 115, 119, 165』

一回目:8の時に
以下のように表示させるにはどうすればよかったでしょうか。
(★):『設定値:1230 詳細値:



   ''' <summary>合計値が完全一致する組み合わせを探す</summary>
    ''' <param name="targetValue">設定値</param>
    ''' <param name="values">値リスト</param>
    ''' <returns>最初に見つけたものを一つだけ返す</returns>
    Public Function FindCombination(ByVal targetValue As Integer, ByVal ParamArray values As Integer()) As Integer()
        If values Is Nothing OrElse values.Length = 0 Then Throw New ArgumentNullException("values")
        'If values.Any(Function(v) v < 10 OrElse v > 9999) Then Throw New ArgumentOutOfRangeException("values", "2〜4桁の自然数が必要です。")
        If values.Any(Function(v) v <= 0) Then Throw New ArgumentOutOfRangeException("values", "自然数が必要です。")

        '設定値を超えるものは除外した上で、[値]の昇順に並べる
        Dim ordered As Integer() = (From v In values Where v <= targetValue Order By v).ToArray()

        '探索処理
        Dim maxIndex = ordered.GetUpperBound(0)
        Dim edge As Node = Nothing  '発見した組み合わせ
        Dim Search As Action(Of Integer, Node) =
            Sub(index, parent)


                Dim a As Integer = 0
                If Not edge Is Nothing Then Return '既に発見済み

                For i = index To maxIndex

                    Dim nextValue = ordered(i)      '値を昇順に抽出
                    Dim nextNode As New Node(parent, nextValue)

                    a = a + 1

                    If nextNode.Total <= targetValue Then
                        parent.Add(nextNode)        '超過しないなら抽出

                        If nextNode.Total = targetValue Then
                            ' edge = nextNode         '目標値に達したので探索終了
                           If a < 10 Then
                                MsgBox(a)
                                edge = nextNode         '目標値に達したので探索終了
                                Return
                            Else
                                Search(i + 1, nextNode) '再帰して次の組み合わせを選ぶ

                            End If

                        Else
                            Search(i + 1, nextNode) '再帰して次の組み合わせを選ぶ

                        End If
                    End If
                Next
            End Sub



        '探索実行
        Dim root As New Node(Nothing, 0)
        Search(0, root)
        If edge Is Nothing Then
            '見つからなかった
            Return New Integer(-1) {}
        Else

            Dim result As New Stack(Of Integer)()
            Dim e = edge
            Do
                result.Push(e.Value)

                e = e.Parent
            Loop Until e Is root
            Return result.ToArray()
        End If
    End Function  

[ツリー表示へ]
タイトルRe^11: 組み合わせ合計検索 つづき
記事No12138
投稿日: 2023/08/30(Wed) 13:18
投稿者魔界の仮面弁士
> 'Console.Write("設定値:{0} ", 設定値)

出力方法を MsgBox に変えたいのであれば、
 Sub 探索(…)

 Function 探索(…) As String
に変更し、戻り値で結果を返すようにした方が良いでしょう。

そうすれば呼び出し元は
 Label1.Text = 探索(1230, 値一覧3)
 MsgBox( 探索(1230, 値一覧3) )
 Debug.WriteLine( 探索(1230, 値一覧3) )
のように、任意の方法で結果を確認できるようになります。


> これを10個以下で詳細値を求めたいと思っています。
No.12102 の実装において、FindCombination 時の再起処理のところで、
Node の階層数が 10 を超過したら探索を打ち切るようにすれば良いでしょう。

探索結果は Node で保持しているので、アイテム数も Node に管理させた方が手っ取り早いです。
たとえば Node クラスに
    Public ReadOnly Property Depth As Integer
        Get
            Return If(Parent Is Nothing, 0, Parent.Depth + 1)
        End Get
    End Property
を追加しておいて、
 If nextNode.Total <= targetValue Then
の部分を
 If nextNode.Total <= targetValue AndAlso nextNode.Depth <= 10 Then
に変更するとか。


これにより
 合計値:1230 詳細値:36, 40, 45, 51, 55, 65, 69, 76, 82, 98, 106, 108, 115, 119, 165

 合計値:1230 詳細値:36, 40, 45, 119, 133, 159, 163, 165, 184, 186
に変化します。アイテム数が 15 個から 10 個に削減されていますね。


実際には、最短で 8 個の組み合わせもありますが(106, 119, 148, 159, 163, 165, 184, 186)、
No.12102 の実装は「最初に発見したところで調査を打ち切る」実装になっているため、このケースでは
10 個の組み合わせ(36, 40, 45, 119, 133, 159, 163, 165, 184, 186)が先に出力されます。

よりアイテム数の少ない組み合わせを優先したい場合は、既に提供済みの
すべての組み合わせを返すバージョンを使うなどしてみてください。


> 以下のように変更した場合
> msgbox の値は以下のようになります。
修正したコードにある、第 3 引数「ByVal kyoyouti As Integer」が謎です。
ここに値を渡している箇所も無ければ、引数値を読み取っている箇所すら見当たりません。

仮変数の名前から "許容値" の意味であることは想像ができますが、
実引数を見ても第 3 引数が指定されていないですよ?
> 探索(1230, 値一覧3)



> 一回目:8
> 二回目:15
今はラムダ式の中で、 MsgBox(a) として、変数 a の値を表示しているだけですよね。
探索結果を表示しないと意味が無いでしょう。

探索結果を格納しているのは Node クラスで、組み合わせを階層構造で保持していますので、
探索後に、Node クラスの中身を調べるようにしてください。
その特性上、幹側から枝側を辿るのではなく、枝側から幹側へ辿る設計です。


なお、たけしさんが書かれた「Dim a As Integer = 0」のカウントアップは、
詳細値の数を意味していないので、実装として間違っています。これについては後述。



> 以下のように表示させるにはどうすればよかったでしょうか。
探索終了時に、edge 変数(あるいは nextNode) の Parent を Do ループで辿れば良いのです。


たとえば 1, 2, 3, 4 の4 つの数値のすべての組み合わせから合計値 5 を探索する場合、
  探索(5, New Integer() {1, 2, 3, 4})
の呼び出しにより、Dim root As Node に対して下記の構造が格納されます。

root
┣Value=1       …  1 = 1
┃┣Value=2     …  3 = 1 + 2
┃┣Value=3     …  6 = 1 + 2 + 3
┃┗Value=4     …  5 = 1 + 4       ※このノードが edge 変数になる
┣Value=2       …  2 = 2
┣Value=3       …  2 = 3
┗Value=4       …  2 = 4

この場合の edge は、2 階層の深さになっているので
 edge.Value + edge.Parent.Value
によって、4 + 1 = 5 という組み合わせを得られます。

[ツリー表示へ]
タイトルRe^12: 組み合わせ合計検索 つづき
記事No12139
投稿日: 2023/08/30(Wed) 18:12
投稿者魔界の仮面弁士
> たとえば 1, 2, 3, 4 の4 つの数値のすべての組み合わせから合計値 5 を探索する場合、
>   探索(5, New Integer() {1, 2, 3, 4})
> の呼び出しにより、Dim root As Node に対して下記の構造が格納されます。

もしも、{ 1, 2, 3, 4 } という 4 つの値すべての組み合わせを得る実装にしていたのであれば、
こういう階層結果が得られていたわけです。


root
┣Value=1       …  1 = 1                 不足
┃┣Value=2     …  3 = 1 + 2             不足
┃┃┣Value=3   …  6 = 1 + 2 + 3        ◇超過
┃┃┃┗Value=4 … 10 = 1 + 2 + 3 + 4    ◇超過
┃┃┗Value=4   …  7 = 1 + 2 + 4        ◇超過
┃┣Value=3     …  4 = 1 + 3             不足
┃┃┗Value=4   …  8 = 1 + 3 + 4        ◇超過
┃┗Value=4     …  5 = 1 + 4            ★合致
┣Value=2       …  2 = 2                 不足
┃┣Value=3     …  5 = 2 + 3            ★合致
┃┃┗Value=4   …  9 = 2 + 3 + 4        ◇超過
┃┗Value=4     …  6 = 2 + 4            ◇超過
┣Value=3       …  3 = 3                 不足
┃┗Value=4     …  7 = 3 + 4            ◇超過
┗Value=4       …  4 = 4                 不足


実際には、合計値が超過した枝はそれ以上生やす必要が無いので、
『If nextNode.Total <= targetValue Then』の枝刈りロジックにより、
◇部は生成されず、下記の構造だけが残ります。

root
┣Value=1       …  1 = 1                 不足
┃┣Value=2     …  3 = 1 + 2             不足
┃┣Value=3     …  4 = 1 + 3             不足
┃┗Value=4     …  5 = 1 + 4            ★合致
┣Value=2       …  2 = 2                 不足
┃┗Value=3     …  5 = 2 + 3            ★合致
┣Value=3       …  3 = 3                 不足
┗Value=4       …  4 = 4                 不足


この場合、合計 5 になる組み合わせとして本来は 1+4 と 2+3 の 2 種類が存在するわけですが、
探索の高速化のため、最初の組み合わせが発見された時点で edge を確定させ、
それ以降は「If Not edge Is Nothing Then Return」によって捜索を打ち切る実装になっています。

そのため、root 変数および edge 変数の階層構造は、下記のようになります。

root
┣Value=1       …  1 = 1                 不足
┃┣Value=2     …  3 = 1 + 2             不足
┃┣Value=3     …  4 = 1 + 3             不足
┃┗Value=4     …  5 = 1 + 4            ★合致(edge 変数)
┣Value=2       …  2 = 2                 不足
┣Value=3       …  3 = 3                 不足
┗Value=4       …  4 = 4                 不足


上図の通り、終端となる edge.Value は 4 を返します。
その親階層を辿ると、edge.Parent.Value は 1 になっています。
さらにその親階層である edge.Parent.Parent は root に当たります。

このことから、この edge は 2 階層であり、それが 1 + 4 の組み合わせを意味しているのだと分かります。

なお、root.Value や edge.Parent.Parent.Value は 0 なので無視できます。
また、root のさらに親は存在していないため、root.Parent や edge.Parent.Parent.Parent は Nothing です。



> なお、たけしさんが書かれた「Dim a As Integer = 0」のカウントアップは、
> 詳細値の数を意味していないので、実装として間違っています。これについては後述。

残念なことに、たけしさんが書かれた「a = a + 1」のカウント方式は、
組み合わせた詳細値の数(Node の階層数 N)を表す処理にはなっていません。

実際には、兄弟の番号をカウントアップしているだけの処理になっています。
(すなわち、N 階層目における A 番目の要素、の意味)


たとえば『探索(5, New Integer() {1, 2, 3, 4})』の場合、
現状の Dim a As Integer は下記のようにカウントされています。


Root
┣Value=1       …  a = 1 (階層数=1) Total = 1
┃┣Value=2     …  a = 1 (階層数=2) Total = 3
┃┣Value=3     …  a = 2 (階層数=2) Total = 4
┃┗Value=4     …  a = 3 (階層数=2) Total = 5
┣Value=2       …  a = 2 (階層数=1) Total = 2
┣Value=3       …  a = 3 (階層数=1) Total = 3
┗Value=4       …  a = 4 (階層数=1) Total = 4


そして、『探索(1230, 値一覧3)』の場合は下記の結果になるでしょう。
それゆえ探索終了時に詳細値が 15 個あっても、MsgBox(a) には「8」と表示されてしまうのです。


Root
┣Value=36                                 … a= 1 (階層数= 1) Total=  36
┃┣Value=40                               … a= 1 (階層数= 2) Total=  76
┃┃┣Value=45                             … a= 1 (階層数= 3) Total= 121
┃┃┃┣Value=51                           … a= 1 (階層数= 4) Total= 172
┃┃┃┃┣Value=55                         … a= 1 (階層数= 5) Total= 227
┃┃┃┃┃┣Value=65                       … a= 1 (階層数= 6) Total= 292
┃┃┃┃┃┃┣Value=69                     … a= 1 (階層数= 7) Total= 361
┃┃┃┃┃┃┃┣Value=76                   … a= 1 (階層数= 8) Total= 437
┃┃┃┃┃┃┃┃┣Value=82                 … a= 1 (階層数= 9) Total= 519
┃┃┃┃┃┃┃┃┃┣Value=98               … a= 1 (階層数=10) Total= 617
┃┃┃┃┃┃┃┃┃┃┣Value=106            … a= 1 (階層数=11) Total= 723
┃┃┃┃┃┃┃┃┃┃┃┣Value=108          … a= 1 (階層数=12) Total= 831
┃┃┃┃┃┃┃┃┃┃┃┃┣Value=115        … a= 1 (階層数=13) Total= 946
┃┃┃┃┃┃┃┃┃┃┃┃┃┣Value=116      … a= 1 (階層数=14) Total=1062
┃┃┃┃┃┃┃┃┃┃┃┃┃:
┃┃┃┃┃┃┃┃┃┃┃┃┃┣Value=119      … a= 3 (階層数=14) Total=1065
┃┃┃┃┃┃┃┃┃┃┃┃┃┃┣Value=123    … a= 1 (階層数=15) Total=1188
┃┃┃┃┃┃┃┃┃┃┃┃┃┃:
┃┃┃┃┃┃┃┃┃┃┃┃┃:┗Value=165    … a= 8 (階層数=15) Total=1230 ★これが edge
┃┃┃┃┃┃┃┃┃┃┃┃:┗Value=186      … a=13 (階層数=14) Total=1132
┃┃┃┃┃┃┃┃┃┃┃:┗Value=186        … a=14 (階層数=13) Total=1017
┃┃┃┃┃┃┃┃┃┃┃┗Value=186          … a=15 (階層数=12) Total= 909
┃┃┃┃┃┃┃┃┃:┗Value=186            … a=16 (階層数=11) Total= 803
┃┃┃┃┃┃┃┃:┗Value=186              … a=17 (階層数=10) Total= 705
┃┃┃┃┃┃┃:┗Value=186                … a=18 (階層数= 9) Total= 623
┃┃┃┃┃┃:┗Value=186                  … a=19 (階層数= 8) Total= 547
┃┃┃┃┃:┗Value=186                    … a=20 (階層数= 7) Total= 478
┃┃┃┃:┗Value=186                      … a=21 (階層数= 6) Total= 413
┃┃┃:┗Value=186                        … a=22 (階層数= 5) Total= 358
┃┃:┗Value=186                          … a=23 (階層数= 4) Total= 307
┃:┗Value=186                            … a=24 (階層数= 3) Total= 262
:┗Value=186                              … a=25 (階層数= 2) Total= 222
┗Value=186                                … a=26 (階層数= 1) Total= 186

[ツリー表示へ]
タイトルRe^12: 組み合わせ合計検索 つづき
記事No12140
投稿日: 2023/08/31(Thu) 15:58
投稿者たけし
お世話になります。


> > これを10個以下で詳細値を求めたいと思っています。
> No.12102 の実装において、FindCombination 時の再起処理のところで、
> Node の階層数が 10 を超過したら探索を打ち切るようにすれば良いでしょう。
>
> 探索結果は Node で保持しているので、アイテム数も Node に管理させた方が手っ取り早いです。
> たとえば Node クラスに
>     Public ReadOnly Property Depth As Integer
>         Get
>             Return If(Parent Is Nothing, 0, Parent.Depth + 1)
>         End Get
>     End Property
> を追加しておいて、
>  If nextNode.Total <= targetValue Then
> の部分を
>  If nextNode.Total <= targetValue AndAlso nextNode.Depth <= 10 Then
> に変更するとか。
>

詳細値:を 多くした場合 198個

182    188    203    33    92    109    131    36    51    55    65    82    86    106    115    129    133    134    139    148    159    165    184    63    29    54    24    68    29    29    54    68    29    68    29    36    45    51    55    65    76    82    89    106    115    116    119    129    133    134    139    142    148    159    165    184    185    186    77    140    217    43    45    64    77    140    155    166    77    140    217    92    75    70    56    50    106    129    163    222    36    51    55    65    69    106    109    113    115    116    119    128    129    133    137    151    159    163    165    182    184    203    205    213    216    219    33    36    40    50    51    55    65    86    89    92    106    109    115    116    119    129    131    133    139    159    163    165    176    184    186    213    216    219    113    186    33    36    55    65    75    92    94    106    115    116    119    129    133    142    159    165    184    186    36    51    55    65    103    106    115    116    119    129    133    159    163    165    184    186    36    50    51    55    65    74    89    106    109    113    115    116    118    119    128    129    133    139    159    163    165    184    186    219    222    256    106    139

以下のエラーでます。

OutOfMemoryException はハンドルされませんでした。
種類 'System.OutOfMemoryExceptin' の例外がスローされました。
件数が悪さしているのでしょうか?

件数がある程度少ないときは成功します。



> よりアイテム数の少ない組み合わせを優先したい場合は、既に提供済みの
> すべての組み合わせを返すバージョンを使うなどしてみてください。

これから試してみようと思っています。


> > 以下のように変更した場合
> > msgbox の値は以下のようになります。
> 修正したコードにある、第 3 引数「ByVal kyoyouti As Integer」が謎です。
> ここに値を渡している箇所も無ければ、引数値を読み取っている箇所すら見当たりません。
>
> 仮変数の名前から "許容値" の意味であることは想像ができますが、
> 実引数を見ても第 3 引数が指定されていないですよ?
> > 探索(1230, 値一覧3)

For 設定値 = 設定値 To 設定値 - 20 Step -1

20の部分を kyoyouti で変更できるようにしていたのですが
書き込む際に消し忘れてしまいました。
        

[ツリー表示へ]
タイトルRe^13: 組み合わせ合計検索 つづき
記事No12141
投稿日: 2023/08/31(Thu) 16:45
投稿者魔界の仮面弁士
> 詳細値:を 多くした場合 198個

えっ。本当にそれだけのものが必要なのですか?

そもそも何のために、今回の『組合せ最適化問題』を解こうとしているのでしょうか。
「XY 問題」に陥ることを防ぐためにも、まずは目的を示していただけますか。



> OutOfMemoryException はハンドルされませんでした。
> 種類 'System.OutOfMemoryExceptin' の例外がスローされました。
> 件数が悪さしているのでしょうか?

高校1年で習う 数学A の組み合わせ計算を思い出してみてください。
要素の数を N とした場合、重複を許さない組み合わせ総数は「((2 の N 乗) - 1) 通り」です。
累乗計算なので、要素数の増加に付けて、組み合わせ数が加速度的に巨大数化していきます。


1 要素の場合、組み合わせ総数は 1 です。
2 要素の場合、組み合わせ総数は 3 です。
3 要素の場合、組み合わせ総数は 7 です。
4 要素の場合、組み合わせ総数は 15 です。
5 要素の場合、組み合わせ総数は 31 です。
10 要素の場合、組み合わせ総数は 1,023 です。
20 要素の場合、組み合わせ総数は 1,048,575 (104万) です。
30 要素の場合、組み合わせ総数は 1,073,741,823 (10億)です。
100 要素の場合、組み合わせ総数は 1,267,650,600,228,229,401,496,703,205,375 (126穣) です。

198 要素の場合、組み合わせ総数は 0.4那由他(4017阿僧祇)です。
※正確には 401,734,511,064,747,568,885,490,523,085,290,650,630,550,748,445,698,208,825,343 通り。

今のロジック(枝切りとか、初回検出で打ち切り)だけでは、
メモリー的にも時間的にも無理がありそうですよね。


No12137 でやろうとしていたように、組み合わせる個数に制限を設けて、
1 個以上 10 個以下 の範囲での調査に制限したとしても、

20 要素では 184,756 (18万) 通り
30 要素では 30,045,015 (3004万) 通り
40 要素では 1,221,246,131 (12億) 通り
50 要素では 13,432,735,555 (134億) 通り
100 要素では 19,415,908,147,835 (19兆)通り
150 要素では 1,258,067,642,133,715 (125兆)通り
198 要素では 21,381,429,129,671,215 (2京)通り
200 要素では 23,683,917,463,480,695 (2京)通り
という、ものすごい量の組み合わせを調査せねばなりません。

※なお、異なる n 個のものの中から異なる r 個を取り出す場合の組み合わせ数は
  nCr = n! / ( r! * (n - r)! )
 で求められます。10 個以下の組み合わせなら nC1 + nC2 + nC3 + … + nC10 なΣ演算。


仮に、一つのノードが 16 バイトを消費していたと仮定すると、
単純計算で、4GB のメモリー消費で保持できる組み合わせは 2.6 億通りしかありません。
さすがに現状の処理では追い付かないので、要件の見直しが必要になりそうですね。

※実際には総当たりでは無く、枝切りロジックを仕込んだり、合致する組み合わせを
 一つ見つけた時点でそこで調査が打ち切るようにはなっていますが、処理時には
 上記以外のメモリー消費も必要であるため、限界性能は単純には算出できません。

[ツリー表示へ]