Разделяй и оставайся счастливым. Кто заботится о части Завоевателя?


12

Что ж, когда я покупаю подарки для двух своих жен, я хочу, чтобы они чувствовали себя одинаково важными для меня, но ходить по магазинам с фиксированным бюджетом сложно. Вместо этого я покупаю кучу вещей и делю их на две группы с максимально возможной ценностью. Тогда я покупаю кучу конфет, чтобы починить все остальное.

Но я не хочу делать всю тяжелую работу, когда мой компьютер может это сделать. И ты тоже. Так что решите эту проблему так, чтобы в следующий раз, когда вам нужно было разделить подарки между вашими женами, вы знали, что это будет легко.

вход

1 массив (N * 2) элементов, где N * 2 указано в 1-й строке.
Элементы массива в следующей строке.

Выход

2 массива из N элементов, каждый из которых таков:
Разница (сумма элементов массива 1) и (сумма элементов массива 2) максимально приближена к 0.

пример

вход

4
1 2 3 4 

Выход

1 4
2 3
diff=0

Отказ от ответственности : у меня нет двух жен. Но когда мне плохо, я представляю себе двух жен. И вдруг я благодарен и счастлив, что у меня есть только один. : D


3
В его нынешнем виде «2 массива из N элементов каждый» заставляет группы быть также равными по размеру. Это предназначено? Например, на данный момент для группы ввода 1 1 1 1 1 5правильный ответ будет 1 1 1| 1 1 5, пока 1 1 1 1 1| 5будет иметь больше смысла.
Шион

Полагаю, что эта проблема также относится к близнецам и, возможно, к другим детям-созвездиям. Рождество сегодня - это в основном событие «он получил больше, чем я» ...
TheConstructor

1
@shiona, да, одинаковый размер предназначен. @ TheConstructor, деление на детей не так забавно, как деление на две жены. : D
rahulroy9202

Для тега code-challenge требуется объективный критерий выигрыша. Также это тесно связано с проблемой подмножества сумм, которая была задана здесь ранее.
Говард

@ Но есть важные отличия от суммы подмножества: вам нужно построить два списка одинакового размера (не только одинакового значения), вам нужно использовать все элементы, ...
TheConstructor

Ответы:


4

Джава

Попытка решить эту проблему в два этапа:

  1. Создайте два одинаковых по размеру списка, добавив оставшийся самый большой в текущий меньший список и следующий рядом с другим. Повторение.
  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 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

Попробуйте онлайн!

Это конкурс популярности, но это не обязательно означает, что языки игры в гольф плохо подходят. (Действительно, я должен был ответить в Jelly, потому что ответы Jelly имеют тенденцию получать непропорциональное количество голосов по какой-то причине, независимо от того, кто их представляет или как они играют в гольф, но Brachylog более читабелен.)

Мы начнем с того, что берем список всех перестановок input ( pᶠ) и разбиваем каждый ( ) на две равные части ( мы могли бы дать ему индекс, если по какой-то причине у вас было более двух жен). Затем мы упорядочиваем расстановку перестановок ( {…}ᵒ), беря сумму ( +) каждой ( ) половины, беря абсолютную разницу (т. Е. 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


Распределение несправедливо? Итак, выбери другое.

@ Конструктор отмечает, что жена 2 может оспаривать тот факт, что жена 1 получила все лучшие активы. Таким образом, следующее производит все «справедливые» (разница = самая низкая разница) акции для жены 1; жена 2 получает оставшиеся активы; ноль относится к разнице в активах для жен. Существует 5448 способов распределения активов с весом от 1 до 20. Отображается только несколько строк.

Формат

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 кажется красивой для такой задачи. И последнее, что настоящие жены, вероятно, будут спорить, так как 5 самых ценных предметов находятся в одном стеке. (Да, с 1 по 20, нет решения без места для споров)
TheConstructor

@ На самом деле, существует несколько способов распределения активов. Я перечислил некоторые из способов в приложении. Примечание: в список включены только активы одной жены; другой получает дополнение.
DavidC

Это одна из причин, по которой я выбираю создание своих начальных стеков так, как я это делаю: обычно две самые ценные вещи не находятся в одном и том же стеке. Ваше первоначальное решение доказывает, что существует 10 пар чисел с суммой 21; Вы неявно выбираете последовательные пары.
TheConstructor

Да, я ценю логику вашего подхода.
DavidC

2

J

По этой ссылке есть шпаргалка со всеми примитивами J , на случай, если вы захотите следовать дома. Помните: J обычно читается справа налево, так что 3*2+1это 7, а не 9. Каждый глагол (J для функции) является либо монадическим, то есть перед подобным f y, либо двоичным, то есть между подобным 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 ; <.является Lesser Of , поэтому <./означает Fold Lesser Of или Minimum .

  • u"1означает «выполнять uна одномерных ячейках», то есть над каждым рядом. Обычно глаголы в J либо атомарные, либо применяются ко всему аргументу. Это относится к обоим аргументам, если глагол используется двоично (с двумя аргументами). Учтите следующее:

       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.

  • /., когда используется двоично, называется ключом . Он использует элементы списка с левой стороны в качестве ключей, а элементы с правой стороны - в качестве значений. Он группирует каждый набор значений, которые разделяют ключ, а затем выполняет с ними некоторую операцию.

    В случае ]/., операция - это просто глагол тождественности, поэтому ничего особенного там не происходит, но факт, /.который разделит список для нас, является важным битом. Вот почему мы создаем двоичные списки: так, чтобы для каждого list ( "1) мы могли делить подарки для жен всеми возможными способами.

  • 1!:1]1и 1!:2&2являются операциями чтения и записи соответственно. 1!:nЧасть является глаголом , а другой номер является дескриптором файла. 1это консоль, 2это консоль, и 3 4 5это stdin, stdout и stderr. Мы также используем ".при чтении, чтобы преобразовать входные строки в числа.


1
+1 за отправку ответа в J и по крайней мере, чтобы сделать его понятным.
Уровень Река St

1

Clojure

(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

добавить метод отображения для печати результата.
Мамун

Результат теперь равный по размеру
Мамун,

Для [1 4 5 6 7 8]вашей программы рассчитано, [8 5 4] [7 6 1] Diff 3где явно существуют решения с разницей в 1.
TheConstructor

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

Предупреждение: очень грязный код.
Он пробует каждую возможную перестановку входного массива.

Идеальный образец для 4/1 2 3 4: http://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]

Или даже дальше, потому что половина линии - это просто макияж. (при условии, что я могу просто сбросить необработанный внутренний массив, так как это не указано в операторе). Вы можете оставить 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))

Например, с помощью этого кода он работает практически без разницы: максимальное значение 500k на 10 ^ 10, так сказать, немного. Это также намного быстрее: там, где другой код, вероятно, не завершится менее чем через год (и это очень оптимистично), это выполняется примерно за полсекунды, даже если ваш пробег может варьироваться.

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?
HyperNeutrino

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.