特定の重みのセットに追加する最適な重みのセットを見つける


8

この課題では、次のように、入力として重みのコンマ区切りリストを受け取ります。

1,3,4,7,8,11

そして、そのセットに追加できる最小量の重みを出力する必要があります。たとえば、このセットの出力は次のようになります

1,3,7

これらの重みをこれら3つだけで表すことができるからです。

1     = 1
3     = 3
1+3   = 4
7     = 7
1+7   = 8
1+3+7 = 11

複数のソリューションが存在する場合があります。例えば、入力のためのソリューションは、1,2可能性があり1,1、または1,2。入力セットを表すことができる重みの最小量が検出される限り、これは有効なソリューションです。

重りを複数回使用することはできません。1つを2回使用する必要がある場合は、2回出力する必要があります。たとえば、2,3はに対して2回2,3,5,7使用できないため、の有効なソリューションではありません。22+2+3=7

入力は、重複した番号がないことが保証されています。

これはので、文字数による最も短いコードが優先されます。

ネットワークアクセスが禁止されている(あなたの「賢い」のどれもそうwgetソリューション@JohannesKuhn 咳 咳);)

最も単純なケース:

1,5,6,9,10,14,15               => 1,5,9
7,14,15,21,22,29               => 7,14,15
4,5,6,7,9,10,11,12,13,15,16,18 => 4,5,6,7
2,3,5,7                        => 2,2,3 or 2,3,7

そして、よりトリッキーなもの:

10,16,19,23,26,27,30,37,41,43,44,46,50,53,57,60,61,64,68,71,77,80,84,87
  => 3,7,16,27,34
20,30,36,50,56,63,66,73,79,86
  => 7,13,23,43
27,35,44,46,51,53,55,60,63,64,68,69,72,77,79,81,86,88,90,95,97,105,106,114,123,132
  => 9,18,26,37,42


@Jan、重要な違いの1つは、引用するチャレンジがセットを要求することですが、これは重複を許可するため(例:7,7,7,8上記)、複雑さが大幅に増大します。
— Cary Swoveland 2013年

入力の重みが一意であると想定できますか?また、ソリューションが特定のテストケースを解決できるようにすることを検討することもできます。そうでない場合、最短の解決策は、小さな問題のみを処理できるブルートフォース列挙子である可能性があります(たとえば、n入力の重みmがあり、最大である場合、サブシーケンスのすべてのサブシーケンスを列挙し(1..m)、各サブシーケンスについて、1とn各インスタンスのすべての組み合わせを列挙しますシーケンスの要素。)
— Cary Swoveland 2013年

@CarySwoveland「ユニークな」部分のために編集されました。私はすでにテストケースを持っています。
— ドアノブ

どのようにして{7,7,7,8}がソリューションになることができますか?8は入力セットにありません。
— DavidC 2013年

回答:


3

Mathematica 80 75

更新:11月5日に追加されたドアノブの挑戦的な最後のテストの更新を下部で参照してください


これは最後のテスト以外はすべて合格です。ただし、数字を2回以上使用することはありません。そして、より大きなデータセットのサブセットであるソリューションからのみ検索します。

この関数は、入力データセットのすべてのサブセットを生成し、完全なセットを構築するために使用できるサブセットをテストします。実行可能なサブセットが見つかると、最小のセットが選択されます。

s=Subsets
f@i_:=GatherBy[Select[s@i,Complement[i, Total /@ s@#]=={}&],Length]〚1〛

テスト

f[{1, 3, 4, 7, 8, 11}]

{{1、3、7}}


f[{1, 5, 6, 9, 10, 14, 15}]

{{1、5、9}}


f[{7, 14, 15, 21, 22, 29}]

{{7、14、15}}


f[{4, 5, 6, 7, 9, 10, 11, 12, 13, 15, 16, 18}]

{{4、5、6、7}}


f[{2, 3, 5, 7}]

{{2、3、5}、{2、3、7}}


更新

以下では、ソリューションの開始に役立つ可能性のある初期分析を提供します。

データ:

data = {10, 16, 19, 23, 26, 27, 30, 37, 41, 43, 44, 46, 50, 53, 57, 60, 61, 64, 68, 71, 77, 80, 84, 87};

以前のアプローチとは異なり、ソリューションセットでは、データセットに表示されない数値を検討します。

このアプローチでは、データセット内の数値のペア間の絶対差を利用します。

g[d_] := DeleteCases[Reverse@SortBy[Tally[Union[Sort /@ Tuples[d, {2}]] /. {a_, b_} :> Abs[a - b]], Last], {0, _}] 

それぞれの違いが現れる回数を見てみましょう。最も一般的な違いから始めて、最初の8つのケースのみを取得します]。

g[data][[1;;8]]

{{7、14}、{27、13}、{34、12}、{3、11}、{20、10}、{16、10}、{4、10}、{11、9}}

14ペアは7だけ異なりました。13ペアは27だけ異なりました。

次に、データセット内のすべての元の要素を説明できるようになるまで、{difference1}、{difference1、difference2}などで始まるサブセットをテストします。

h サブセットからの合計を構成することによって構築できない元のセットからのそれらの数を明らかにします。

h[t_] := Complement[data, Total /@ Subsets@t]

5回目の試行までに、{7、27、34、3、20}から形成できない要素がまだ10個あります。

h[{7, 27, 34, 3, 20}]

{16、19、26、43、46、53、60、77、80、87}

しかし、次の試みでは、データセットのすべての数が考慮されます。

h[{7, 27, 34, 3, 20, 16}]

{}

これはまだ{3,7,16,27,34}ほど経済的ではありませんが、近いです。


考慮すべきいくつかの追加事項があります。

  1. データセットに1がある場合、ソリューションセットでも1が必要です。
  2. 元のセットには、最も一般的な違いから構成できない "loners"が含まれている可能性があります。これらは、差異テストとは別に含める必要があります。

これらは、現在私が処理できる以上の問題です。しかし、私はそれがこの非常に興味深い課題にいくつかの光を投げかけることを望みます。


うーん...現在、重複を必要とするテストケースを考案しています:P
— ドアノブ

今のところ、解決策を投稿したままにし、重複をテストするための条件を追加できるかどうかを確認します。
— DavidC 2013年

3
重みwが繰り返されるソリューションが存在する場合、以前に使用したすべての場所を使用できるため、wの1 つがに変更された同じソリューション2 * wも機能し2 * wますw + w。これは、解が繰り返されなくなるまで繰り返すことができます。したがって、繰り返しを使用する必要はありません。
— cardboard_box

括弧は本当に必要ありません。取得s=Subsets;機能のうち
— 博士ベリサリウス

かっこについてです。
— DavidC 2013年

0

ルビー289

これは単純な列挙であるため、最小限の解決策が得られますが、いくつかの問題を解決するには数年(おそらく数年)かかる場合があります。すべての「最も単純なケース」は、せいぜい数秒で解決します(ただし、3番目と5番目のケースでは、それぞれ7,8,14と1,2,4が得られました)。トリッキー#2は約3時間で解決しましたが、他の2つは列挙するには大きすぎます。少なくとも、私が行った方法ではそうではありません。

nその要素のサブセットを合計することによって特定の配列を生成するサイズの配列は、それを行うサイズの配列がないことが示される場合、最小サイズです< n。最適性を証明する他の方法がないので、既知の下限mであるのサイズのサブセットから列挙を開始し、サイズのサブセットを列挙しm、指定されm+1たm「スパン」のどれもないことを示した後、サイズを増やします配列など、最適なものが見つかるまで。もちろん、サイズnまでのすべてのサブセットを列挙した場合、サイズn + 1のヒューリスティックを使用できるため、そのサイズのスパニング配列が見つかった場合、それが最適であることがわかります。一般的なケースでソリューションが最適であることを証明する別の方法を誰かが提案できますか?

一部の組み合わせを早期に排除するために、いくつかのオプションのチェックを含めました。これらのチェックを削除すると、87文字が節約されます。それらは次のとおりです(a指定された配列です)。

  • サイズの配列はn、最大で2^n-1明確な正の数を生成できます。したがって、2^n-1 >= a.sizeまたはn >= log2(a.size).ceil(私が上記で参照した「下限」)。
  • bサイズの候補生成配列は次のn場合に除外できます。
    • b.min > a.min
    • sum of elements of b < a.max または
    • b.max < v、v = a.max.to_f/n+(n-1).to_f/2.ceil(to_fフロートへの変換です)。

最初にチェックされるこれらの最後は実装します

sum of elements of b <= sum(b.max-n+1..b.max) < a.max

vサイズのすべてのジェネレータ配列について、注意が必要nです。

また、@ cardboard_boxの非常に有益な観察結果を利用して、生成する配列の重複を考慮する必要がないことを確認しました。

私のコードでは、

(1..a.max).to_a.combination(n) 

一度にa.max取らnれた1からの数値のすべての組み合わせを生成します(ここでa.max = a.last = a[-1])。各組み合わせについてb:

(1...2**n).each{|j|h[b.zip(j.to_s(2).rjust(n,?0).split('')).reduce(0){|t,(u,v)|t+(v==?1?u:0)}]=0}

のh空でないサブセットの合計であるすべての数値でハッシュを埋めbます。ハッシュキーはそれらの数値です。値は任意です。(後者をゼロに設定することを選択しました。)

a.all?{|e|h[e]}}

与えられた配列のすべての要素がaハッシュのキーであるかどうかをチェックします(h[e] != nilまたはh[e])。

と思います

n = 3 and b=[2,5,7].

次に、範囲を反復処理します。

(1...2**8) = (1...8) # 1,2,..,7

この範囲の各数値のバイナリ表現はb、合計の要素を突き出すために使用されます。用j = 3(jレンジ指数です)、

3.to_s(2)                  # =>  "11"
"11".rjust(3,?0)           # => "011"
"011".split('')            # => ["0","1","1"]
[2,5,7].zip(["1","0","1"]) # => [[2,"0"],[5,"1"],[7,"1"]]
[[2,"0"],[5,"1"],[7,"1"]].reduce(0){|t,(u,v)|t+(v==?1?u:0)}]=0 # => t = 0+5+7 = 12 

コード:

x=a[-1]
n=Math.log2(a.size).ceil
loop do
v=(1.0*x/n+(n-1)/2.0).ceil
(1..x).to_a.combination(n).each{|b|
next if b[-1]<v||b[0]>a[0]||b.reduce(&:+)<x
h={}
(1...2**n).each{|j|h[b.zip(j.to_s(2).rjust(n,?0).split('')).reduce(0){|t,(u,v)|t+(v==?1?u:0)}]=0}
(p b;exit)if a.all?{|e|h[e]}}
n+=1
end
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.