分开并保持快乐。谁在乎征服部分?


12

好吧,当我为两个妻子购买礼物时,我希望它们对我来说同样重要,但是很难以固定的预算购物。取而代之的是,我买了一堆东西,将它们分成两组,并尽可能地赋予它们相等的价值。然后我买了一束巧克力来修复其余的巧克力。

但是我不想在我的计算机可以做到的时候做所有的努力。而且你也不是。因此,请解决此问题,以便下次您需要在妻子之间分配礼物时,您会知道这很容易。

输入值

(N * 2)个元素的1个数组,其中在第一行中指定了N * 2。
下一行中数组的元素。

输出量

N个元素的2个数组,每个数组使得:(
数组1的元素之和)与(数组2的元素之和)的差尽可能接近0。

输入值

4
1 2 3 4 

输出量

1 4
2 3
diff=0

免责声明:我没有两个妻子。但是当我感到难过时,我想象有两个妻子。突然,我很感激和高兴,因为我只有一个。:D


3
就目前而言,“每个数组由N个元素组成2个数组”迫使组的大小也相等。这是故意的吗?例如,目前输入组1 1 1 1 1 5的正确答案是1 1 1| 1 1 5,而1 1 1 1 1| 5会更有意义。
shiona 2014年

猜猜这个问题也适用于双胞胎,也可能适用于其他儿童星座。今天的圣诞节主要是“他得到的比我更多”的事件……
TheConstructor 2014年

1
@shiona,是的,预期大小相等。@ TheConstructor,在孩子之间划分不如在两个妻子之间划分有趣。:D
rahulroy9202,2014年

标签代码挑战需要客观的获胜标准。这也与之前在这里提出的子集和问题密切相关。
霍华德

@Howard子集总和有重要区别:您需要构建两个大小相等的列表(不仅值相等),还需要使用所有元素,...
TheConstructor 2014年

Answers:


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

Brachylog 2

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

在线尝试!

这是一场人气比赛,但这并不一定意味着打高尔夫球是不合适的。(实际上,我应该在Jelly中回答,因为无论出于何种原因,Jelly的答案都倾向于获得不成比例的投票,而不管是谁提交的或打高尔夫球的方式如何,但Brachylog更具可读性。)

我们从获取输入(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,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 2014年

这就是我选择构建初始堆栈的原因之一:通常,两个最有价值的东西不在同一堆栈中。您最初的解决方案证明有10对数字之和为21;您隐式选择连续对。
TheConstructor 2014年

是的,我感谢您采用这种方法的逻辑。
DavidC

2

Ĵ

如果您想在家中学习,此链接上有所有J基本语的备忘单。切记:J通常是从右到左读取,因此3*2+1是7,而不是9。每个动词(表示功能的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 PlusSum<.较小的,因此<./表示较小的折叠最小

  • 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将使您获得每个length的二进制字符串n

  • /.dyadually使用时,称为Key。它使用左侧列表的元素作为键,使用右侧的元素作为值。它将共享密钥的每组值组合在一起,然后对它们执行一些操作。

    在的情况下]/.,该操作仅是标识动词,因此在那里没有发生任何特别的事情,但是/.为我们划分列表的事实是重要的一点。这就是为什么我们创建二进制列表的原因:这样,对于每个列表("1),我们都可以以各种可能的方式分配给妻子的礼物。

  • 1!:1]11!:2&2分别是读和写操作。该1!:n部分是动词,另一个数字是文件句柄。1是console in,2是console out,3 4 5是stdin,stdout和stderr。我们".在阅读时也会使用,以便将输入字符串转换为数字。


1
+1用于提交J和“至少尝试”答案以使其易于理解。
级圣河

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 2014年

添加显示方法以打印结果。
马蒙2014年

结果集现在大小相等
Mamun 2014年

对于[1 4 5 6 7 8]您的程序,计算出[8 5 4] [7 6 1] Diff 3明显存在差异为1的解决方案。
TheConstructor 2014年

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 2014年

不,不是正方形吗?但是现在我看到项目数应该在第一行。我会改变它。
mmumboss 2014年

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

蟒蛇:

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中指定)。您可以省略printin(例如)交互式shell,并在需要时添加一个[::-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并不多。这也快了很多:如果其他代码可能在不到一年的时间内无法完成(这是非常乐观的),那么即使您的使用年限可能有所不同,也要花大约半秒钟的时间。

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

识字的Haskell

> import Data.List
> import Data.Function

我利用列表monad对其进行了拆分。

> 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 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.