分割して幸せを保ちましょう。征服の部分は誰が気にしますか?


12

まあ、2人の妻のためにギフトを購入するとき、私にも同じように大切に感じてほしいのですが、決まった予算で買い物をするのは難しいです。代わりに、私はたくさんのものを購入し、それらを可能な限り同じ価値を持つ2つのグループに分けます。それから私はチョコレートをたくさん買って残りを修正します。

しかし、コンピューターができる限りすべての苦労をしたくありません。そして、あなたもそうではありません。したがって、この問題を解決して、次に妻に贈り物を分ける必要があるときに、それが簡単であることを知ってください。

入力

1行目にN * 2が指定されている(N * 2)要素の1つの配列。
次の行の配列の要素。

出力

それぞれN要素の2つの配列:(
配列1の要素の合計)と(配列2の要素の合計)の差が可能な限り0に近い

入力

4
1 2 3 4 

出力

1 4
2 3
diff=0

免責事項:私には妻が2人いません。しかし、気分が悪いときは、妻が2人いることを想像します。そして突然、私は自分が1人しかいないことに感謝し、幸せです。:D


3
現状では、「Nエレメントごとに2つの配列」により、グループのサイズも等しくなります。これは意図したものですか?たとえば、入力グループの現時点では、1 1 1 1 1 5正解は1 1 1| 1 1 51 1 1 1 1| 5より理にかなっています。
潮ona 14年

この問題は双子にも当てはまり、おそらく他の子供たちの星座にも当てはまります。クリスマスの今日は...「彼はme'イベントよりも多くなったほとんどである
TheConstructor

1
@shiona、はい、等しいサイズが意図されています。@ TheConstructor、子供の間で分割することは、2人の妻の間で分割するほど面白くありません。:D
rahulroy9202 14年

タグコードチャレンジには、客観的な勝利基準が必要です。また、これは以前にここで尋ねられたサブセット合計問題と密接に関連しています。
ハワード14年

@Howardサブセット合計に重要な違いがあります:あなたは2つの等しくサイズのリストを(ちょうど同じように評価されていない)、あなたはすべての要素を使用する必要が構築する必要があり、...
TheConstructor

回答:


4

Java

この問題を2段階で解決しようとしています。

  1. 残りの最大のリストを現在の小さなリストに追加し、次のリストを次のリストに追加して、2つの同じサイズのリストを作成します。繰り返す。
  2. 価値の違いを減らすために切り替えることができる両方のリストから項目を特定します

のような入力

8
1 2 3 4 5 6 7 8

フェーズ1の後、たとえば

2 3 5 8
1 4 6 7
diff=0

のような入力

6
1 4 5 6 7 8

両方のフェーズが必要になるため、

1 5 8
4 6 7
diff=3

(フェーズ1の後)の結果になります

1 6 8
4 5 7
diff=1

この試みが常に解決策を提供することは保証できますが、すべての場合に最適な解決策が見つかることを証明することはできません。ただし、サイズが等しいリストの制限により、残されたコーナーケースがないことが非常に現実的に感じられます。間違っていることを証明してください;-)

ideone.comのプログラム

import java.util.*;

/**
 * Created to solve http://codegolf.stackexchange.com/q/23461/16293 .
 */
public class EqualSums {

    public static void main(String[] args) {
        final Scanner s = new Scanner(System.in);
        // Read number of elements to divide
        final int count = s.nextInt();
        if (count % 2 == 1) {
            throw new IllegalStateException(count + " can not be divided by 2. Consider adding a 0 value.");
        }
        // Read the elements to divide
        final SortedList valueStack = new SortedList(count);
        for (int i = 0; i < count; i++) {
            valueStack.add(s.nextLong());
        }

        final SortedList targetOne = new SortedList(count / 2);
        final SortedList targetTwo = new SortedList(count / 2);
        // Divide elements into two groups
        addInPairs(targetOne, targetTwo, valueStack);
        // Try to ensure groups have equal value
        retaliate(targetOne, targetTwo);

        // Output result
        System.out.println(targetOne);
        System.out.println(targetTwo);
        System.out.println("diff=" + Math.abs(targetOne.getSum() - targetTwo.getSum()));
    }

    private static void addInPairs(SortedList targetOne, SortedList targetTwo, SortedList valueStack) {
        SortedList smallerTarget = targetOne;
        SortedList biggerTarget = targetTwo;
        while (!valueStack.isEmpty()) {
            // Add biggest remaining value to small target
            smallerTarget.add(valueStack.removeLast());

            // Add second biggest remaining value to big target
            biggerTarget.add(valueStack.removeLast());

            // Flip targets if roles have changed
            if (smallerTarget.getSum() > biggerTarget.getSum()) {
                final SortedList temp = smallerTarget;
                smallerTarget = biggerTarget;
                biggerTarget = temp;
            }
        }

    }

    private static void retaliate(SortedList targetOne, SortedList targetTwo) {
        long difference;
        boolean changed;
        outer:
        do {
            difference = Math.abs(targetOne.getSum() - targetTwo.getSum());
            if (difference == 0) {
                return;
            }
            changed = false;
            // Try to find two values, that reduce the difference by changing them between targets
            for (Long valueOne : targetOne) {
                for (Long valueTwo : targetTwo) {
                    final Long tempOne = targetOne.getSum() + valueTwo - valueOne;
                    final Long tempTwo = targetTwo.getSum() - valueTwo + valueOne;
                    if (Math.abs(tempOne - tempTwo) < difference) {
                        targetOne.remove(valueOne);
                        targetTwo.add(valueOne);
                        targetTwo.remove(valueTwo);
                        targetOne.add(valueTwo);
                        changed = true;
                        continue outer;
                    }
                }
            }
        } while (changed);
    }

    public static class SortedList extends AbstractList<Long> {

        private final ArrayList<Long> list;
        private long sum = 0;

        public SortedList(int count) {
            list = new ArrayList<>(count);
        }

        // the next functions access list-field directly
        @Override
        public Long get(int index) {
            return list.get(index);
        }

        @Override
        public boolean add(final Long t) {
            final int i = Collections.binarySearch(list, t);
            if (i < 0) {
                // No equal element present
                list.add(-i - 1, t);
            } else {
                list.add(afterLastEqual(i, t), t);
            }
            sum += t;
            return true;
        }

        @Override
        public Long remove(int index) {
            final Long old = list.remove(index);
            sum -= old;
            return old;
        }

        @Override
        public int size() {
            return list.size();
        }

        // the next functions access list-field only through the functions above this point
        // to ensure the sum is well kept

        public long getSum() {
            return sum;
        }

        private int afterLastEqual(final int start, Object o) {
            int found = start;
            while (found < size() && o.equals(get(found))) {
                found++;
            }
            return found;
        }

        private int beforeFirstEqual(final int start, final Object o) {
            int found = start;
            while (found >= 0 && o.equals(get(found))) {
                found--;
            }
            return found;
        }

        @Override
        public int indexOf(Object o) {
            try {
                final int i = Collections.binarySearch(this, (Long) o);
                if (i >= 0) {
                    return beforeFirstEqual(i, o) + 1;
                }
            } catch (ClassCastException e) {
                // Object was not instance of Long
            }
            return -1;
        }

        @Override
        public int lastIndexOf(Object o) {
            try {
                final int i = Collections.binarySearch(this, (Long) o);
                if (i >= 0) {
                    return afterLastEqual(i, o) - 1;
                }
            } catch (ClassCastException e) {
                // Object was not instance of Long
            }
            return -1;
        }

        @Override
        public boolean remove(Object o) {
            if (o == null) {
                return false;
            }
            final int i = indexOf(o);
            if (i >= 0) {
                remove(i);
                return true;
            }
            return false;
        }

        public Long removeLast() {
            return remove(size() - 1);
        }

        public Long removeFirst() {
            return remove(0);
        }

        @Override
        public String toString() {
            Iterator<Long> it = iterator();
            if (!it.hasNext()) {
                return "";
            }

            StringBuilder sb = new StringBuilder();
            for (; ; ) {
                Long e = it.next();
                sb.append(e);
                if (!it.hasNext()) {
                    return sb.toString();
                }
                sb.append(' ');
            }
        }
    }
}

3

ブラキログ 2

pᶠḍᵐ{+ᵐo-}ᵒh

オンラインでお試しください!

これは人気のコンテストですが、必ずしもゴルフの言語が合わないというわけではありません。(ジェリーの回答は、誰が提出したか、どのようにゴルフされたかに関係なく、何らかの理由で不均衡な数の賛成票を取得する傾向があるため、ゼリーで答えるべきでしたが、ブラキログは読みやすいです)

まず、入力のすべての順列のリスト(pᶠ)を取得し、各()を2つの等しい部分に分割します(何らかの理由で2人以上の妻がいる場合は、添え字を付けることができます)。次に、各()半分{…}ᵒの合計(+)を取り、絶対差(つまりo-「順序付けられた差」)を取り、それらの差を使用してソート順を定義することにより、分割順列()を順序付けます。最良の結果は最初の結果であるため、リストの先頭hを取得して結果を取得します。


2

Mathematica

入力フォーム

入力文字列は、STDINを介して取得されます。 assets妻(または双子)に分配される金額を指します。 length資産の数です。

assets=ToExpression[Rest[s=StringSplit[input]]]
length=ToExpression[First[s]]

現在の目的のために、資産は1〜20の整数で構成されていると仮定します。

assets=Range[20];
length=Length[Range[20]]

処理

(* find all possible distributions to one wife; the other presumably gets the remaining assets *)
r=Subsets[assets,{length/2}];

(*order them according to the difference with respect to the total of half of the assets. 
Remove the first set of assets.  One wife will get these.*)
s=SortBy[r/.{{a__Integer}:> {{a},Abs[Tr[Range[20]/2]-Tr[{a}]]}},Last][[1]];

(*The other wife's assets will be the complement.  The difference is carried over from the sorting routine. *)
Grid[{{Grid[{s[[1]],Complement[assets,s[[1]]]}]},{"difference = "<>ToString[s[[2]]]}}]

r20


分布は不公平ですか?だから、別のものを選択してください。

@The Constructorは、妻1がすべての最高の資産を得たという事実に妻2が異議を唱える可能性があることに注意します。したがって、次の例では、妻1のすべての「公平」(差=最小差)シェアが生成されます。妻2は残りの資産を取得します。ゼロは、妻の資産の違いを指します。1から20に重み付けされた資産を配布するには5448の方法があります。数行のみが表示されます。

形式は

s=SortBy[r/.{{a__Integer}:> {{a},Abs[Tr[Range[20]/2]-Tr[{a}]]}},Last];
z=Cases[s,{_List,x_}/;x==s[[1,2]]];
Short[z,10]
Length[z]

{{{1,2,3,4,5,16,17,18,19,20}、0}、{{1,2,3,4,6,15,17,18,19,20}、 0}、{{1,2,3,4,7,14,17,18,19,20}、0}、{{1,2,3,4,7,15,16,18,19,20 }、0}、{{1,2,3,4,8,13,17,18,19,20}、0}、{{1,2,3,4,8,14,16,18,19 、20}、0}、{{1,2,3,4,8,15,16,17,19,20}、0}、{{1,2,3,4,9,12,17,18 、19,20}、0}、{{1,2,3,4,9,13,16,18,19,20}、0}、{{1,2,3,4,9,14,15 、18、19、20}、0}、{{1,2,3,4,9,14,16,17,19,20}、0}、{{1,2,3,4,9,15 、16、17、18、20}、0}、{{1,2,3,4,10,11,17,18,19,20}、0}、{{1,2,3,4,10 、12、16、18、19、20}、0}、<< 5420 >>、{{5,6,7,8,9,11,13,14,15,17}、0}、{{5 、6、7、8、9、12、13、14、15、16}、0}、{{5、6、7、8、10、11、12、13、14、19}、0}、{ {5,6,7,8,10,11,12,13,15,18}、0}、{{5,6,7,8,10,11,12,13,16,17}、0} 、{{5,6,7,8,10,11,12,14,15,17}、0}、{{5,6,7,8,10,11,13,14,15,16}、 0}、{{5,6,7,9,10,11,12,13,14,18}、0}、{{5,6,7,9,10,11,12,13,15,17 }、0}、{{5,6,7,9,10,11,12,14,15,16}、0}、{{5,6,8,9,10,11,12,13,14 、17}、0}、{{5,6,8,9,10,11,12,13,15,16}、0}、{{5,7,8,9,10、11,12,13,14,16}、0}、{{6,7,8,9,10,11,12,13,14,15}、0}}

5448


過去の提出は編集の中で見つけることができます。に依存しているため、はるかに非効率的Permutationsです。


Mathematicaはそのようなタスクには美しいようです。最後の1つは、最も価値のある5つのアイテムがすべて1つのスタックにあるため、本当の妻はおそらく議論するということです。(ええ、1〜20で、議論の余地のない解決策はありません)
TheConstructor 14年

@実際には、アセットを配布する方法はかなりあります。補遺にいくつかの方法をリストしました。注:1人の妻の資産のみがリストされています。もう一方は補数を取得します。
DavidC 14年

それが、私が初期スタックを構築することを選んだ理由の1つです。したがって、通常、2つの最も価値のあるものは同じスタック上にありません。最初の解決策は、合計が21の数値のペアが10個あることを証明します。暗黙的に連続したペアを選択します。
TheConstructor 14年

はい、あなたのアプローチの論理に感謝します。
DavidC

2

J

このリンクには、自宅でフォローしたい場合に備えて、すべてのJプリミティブのチートシートがあります。覚えておいてください:Jは通常、右から左に読まれるので、3*2+19ではなく7です。すべての動詞(関数のJ)は単項であるため、前のようにf y、または二項であるので、likeのようになりx f yます。

N =: (". 1!:1 ] 1) % 2          NB. number of items per wife
S =: ". 1!:1 ] 1                NB. list of items to distribute

bins =: #: i. 2 ^ 2*N           NB. all binary strings of length 2n
even =: bins #~ N = +/"1 bins   NB. select those with row-sum 1

NB. all distributions of equal numbers of items to each wife
NB. resultant shape: a list of 2xN matrices
NB. this /. adverb is where all the magic happens, see below
dist =: even ]/."1 S

diff =: | -/"1 +/"1 dist        NB. difference in wives' values
idx  =: (i. <./) diff           NB. index of the lowest difference

1!:2&2 idx { dist               NB. print the winning distribution of items
1!:2&2 'diff=', idx { diff      NB. and the difference of that distribution

メモと説明:

  • u/は「折り返すu」ことを意味するため、リスト内の各要素に対してバイナリ演算を実行します。したがって、たとえば:+/Fold PlusまたはSumを意味します。<.より小さいので、Fold Lesser OfまたはMinimumを<./意味します。

  • u"1u1次元のセルで実行」、つまりすべての行で実行することを意味します。通常、Jの動詞はアトミックであるか、引数全体に適用されます。これは、動詞が2つの引数を使用して動的に使用される場合、両方の引数に適用されます。以下を考慮してください。

       i. 2 3        NB. just a 2x3 matrix of numbers
    0 1 2
    3 4 5
       +/   i. 2 3   NB. Sum the items
    3 5 7
       +/"1 i. 2 3   NB. Sum the items of each row
    3 12
    
  • #:は、数値をバイナリ表現に展開する動詞です。複数の要素を持つリストで使用すると、すべての数値が適切に整列#:i.2^nされるため、長さのすべてのバイナリ文字列が取得されますn

  • /.、通常使用される場合、Keyと呼ばれます。左側のリストの要素をキーとして使用し、右側の要素を値として使用します。キーを共有する値の各セットをグループ化し、それらに対して何らかの操作を実行します。

    の場合]/.、操作は単なるアイデンティティ動詞であるため、そこで何も特別なことは起き/.ていませんが、私たちのためにリストを分割するという事実は重要です。これがバイナリリストを作成する理由です。リスト("1)ごとに、あらゆる方法で妻への贈り物を分割することができます。

  • 1!:1]1および1!:2&2は、それぞれ読み取りおよび書き込み操作です。1!:n一部は動詞であり、他の数は、ファイルハンドルです。1コンソール入力、2コンソール3 4 5出力、標準入力、標準出力、標準エラー出力です。また".、読み取り時に使用して、入力文字列を数値に変換します。


1
JおよびAT LEAST TRYINGで回答を送信して理解できるようにするための+1。
レベルリバーセント14年

1

クロージュア

(defn divide [n]
 (loop [lv [] rv [] d (reverse (sort n))]
  (if (empty? d)
   [lv rv]
   (if (> (reduce + lv) (reduce + rv))
     (if (>= (count lv ) (count rv))
       (recur lv (conj rv (first d)) (into [] (rest d)))
       (recur (conj lv (last d)) rv (pop d))) 
     (if (<= (count lv ) (count rv))
       (recur (conj lv (first d)) rv (into [] (rest d)) )
       (recur lv (conj rv (last d)) (pop d)))))))


 (defn display [[f s]]
   (println f)
   (println s)
   (println (str "Diff " (- (reduce + f) (reduce + s)))))

テスト

 (->> 
 [5 1 89 36 2 -4 20 7]
 divide 
 display)


 =: [89 -4 1 2]
    [36 20 7 5]
    Diff 20

結果セットのサイズは等しく、各セット内の値の差を印刷する必要があります。結果から判断するideoneのクイックテストあなたは両方のポイントを逃したかもしれない
TheConstructor

結果を印刷するための表示メソッドを追加します。
マムン14年

結果セットのサイズが同じになりました
マムン

以下のための[1 4 5 6 7 8]計算プログラム[8 5 4] [7 6 1] Diff 3明確に1が存在の違いとソリューション。
TheConstructor 14年

1

MATLAB

私の解決策は次のとおりです。

%input array
presents=zeros(2,8);
presents(1,1)=8; %number of presents
presents(2,:)=[1 2 7 4 5 3 2 8]; %list of presents

%calculate the cumulative sum of all permutations
%its all about the gift values
how_many=presents(1,1);
options=perms(presents(2,:);
subtotals=cumsum(options,2);

%find the first index where the difference between the two parts is minimal
%makes both wives happy!!
[~, double_happiness] = min(abs(sum(presents(2,:))/2-subtotals(:,how_many/2)));

%create the present lists for Jennifer and Kate :)
for_jennifer=options(double_happiness,1:how_many/2)
for_kate=options(double_happiness,how_many/2+1:end)

たとえば、ソースコードの現在のリストの結果は次のとおりです。

for_jennifer =

     8     2     5     1


for_kate =

     4     7     2     3

両方とも16です。

あまり楽しくないコードをゴルフでプレイすると、最適化されていない132文字が得られます。それを破る;)

function f(p);o=perms(p(:,2));s=cumsum(o,2);[~,d]=min(abs(sum(p(:,2))/2-s(:,p(1,1)/2)));a={o(d,1:p(1,1)/2);o(d,p(1,1)/2+1:end)};a{:}

入力配列は正方でなければなりません。
DavidC

いいえ、正方形ではありませんか?しかし、今ではアイテムの数が最初の行にあるはずです。変更します。
mmumboss

0

PHP

警告:非常にダーティなコード
入力配列のあらゆる可能な順列を試みます。

Ideoneサンプル4/1 2 3 4http : //ideone.com/gIi174

<?php
// Discard the first input line! It's useless :)
fgets(STDIN);
$numbers = explode(' ', rtrim(fgets(STDIN)));
$valuePerWife = array_sum($numbers) / 2;

// Taken from here: http://stackoverflow.com/a/13194803/603003
// Credits to dAngelov: http://stackoverflow.com/users/955185/dangelov
function pc_permute($items, $perms = array( )) {
    if (empty($items)) {
        $return = array($perms);
    }  else {
        $return = array();
        for ($i = count($items) - 1; $i >= 0; --$i) {
             $newitems = $items;
             $newperms = $perms;
         list($foo) = array_splice($newitems, $i, 1);
             array_unshift($newperms, $foo);
             $return = array_merge($return, pc_permute($newitems, $newperms));
         }
    }
    return $return;
}


foreach (pc_permute($numbers) as $permutation) {
    $sum = 0;
    $rest = [];

    for ($i=0; $i<count($permutation); $i++) {
        $sum += $permutation[$i];
        if ($sum == $valuePerWife) {
            $rest = array_slice($permutation, $i + 1);
            break;
        }
    }

    if (array_sum($rest) == $valuePerWife) {
        echo implode(' ', array_slice($permutation, 0, $i + 1)), "\n";
        echo implode(' ', array_slice($permutation, $i + 1)), "\n";
        echo 'diff=0';
        exit;
    }
}
exit('DIDNT FOUND ANY COMBINATION!');

0

Python:

import itertools as t
raw_input()
a=[int(i) for i in raw_input().split()]
a=list(t.permutations(a))
b=len(a[0])/2
c=[(d[b:],d[:b]) for d in a]
d=[abs(sum(d[b:])-sum(d[:b])) for d in a]
e=zip(d,c)
e.sort()
print " ".join([str(i) for i in e[0][1][0]])
print " ".join([str(i) for i in e[0][1][1]])
print "diff",e[0][0]

または少しゴルフ化:

import itertools as t
b=int(raw_input())/2
e=[(abs(sum(d[b:])-sum(d[:b])),(d[b:],d[:b])) for d in t.permutations([int(i) for i in raw_input().split()])]
e.sort()
f=e[0]
g=f[1]
print " ".join([str(i) for i in g[0]]),"\n"," ".join([str(i) for i in g[1]]),"\n","diff=",f[0]

または、さらに半分のラインがメイクアップであるため、さらにゴルフ化され​​ました。あなたが離れて残すことができます(これはOPで指定されていないので、私はちょうど、生の内部配列をダンプすることができます仮定して)print対話型シェル(例えば)で、かつ追加[::-1](最後に、後に[0]あなたが本当にしたい場合)最後の差分。

import itertools as t
b=int(raw_input())/2
print sorted([(abs(sum(d[b:])-sum(d[:b])),(d[b:],d[:b])) for d in t.permutations([int(i) for i in raw_input().split()])])[0]

(結果は(0, ((1, 2, 7, 8), (3, 4, 5, 6)))

ただし、これは考えられるすべての組み合わせを総当たり攻撃するだけであり、リモートで効率的とは見なされません。ただし、リストの長さが同じであっても問題ない場合は、これも機能します(大きな配列で)。

raw_input()
a,b=[],[]
for i in sorted([int(i) for i in raw_input().split()])[::-1]:
    b.append(i)
    if sum(b)>sum(a): b,a=a,b
print a,b,abs(sum(b)-sum(a))

たとえば、この下のコードでは、わずかな違いで実行されます。10^ 10の最大値で500kはそれほど多くありません。また、これははるかに高速です。他のコードがおそらく1年以内に終了しない場合(そしてそれは非常に楽観的です)、これはあなたのマイレージが異なる場合でも、約0.5秒で実行されます。

def raw_input():
    import random
    return " ".join([str(random.randint(1,10**10)) for _ in range(10000)])

raw_input()
a,b=[],[]
for i in sorted([int(i) for i in raw_input().split()])[::-1]:
    b.append(i)
    if sum(b)>sum(a): b,a=a,b
print a,b,abs(sum(b)-sum(a))

質問:これはなぜCW投稿なのですか?
ハイパーニュートリノ

0

文芸ハスケル

> import Data.List
> import Data.Function

リストモナドを使用して分割しました。

> divide []=return ([], [])
> divide (x:xs)=do
>   (w1, w2) <- divide xs
>   [(x:w1, w2), (w1, x:w2)]

次に、評価者を作成します。

> rating (w1, w2)=abs $ (sum w1) - (sum w2)

そして、違いを最小化する関数。

> best = minimumBy (compare `on` rating) . filter (\(x,y)->length x == length y)

そして、それらすべてを組み合わせたもの。

> bestDivison=best . divide

次にパーサー。

> parse::String->[Int]
> parse=fmap read . words

そして、出力フォーマッタ。

> output (w1,w2)=unlines [unwords (map show w1)
>                        , unwords ( map show w2)
>                        , "diff="++(show $ abs $ (sum w1) - (sum w2))]

そして今、プログラム

> main = do
>   getLine --Ignored, I don't need the arrays length
>   input <- fmap parse getLine
>   putStrLn "" --For readability
>   putStrLn $ output $ bestDivison input

例:

λ <*Main>: main
8
5 1 89 36 2 -4 20 7

5 36 20 7
1 89 2 -4
diff=20

結果セットは同じサイズのものでなければならない
TheConstructor
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.