子集总和的N位变化


14

对于我正在编写的另一个挑战,我需要验证测试用例是否可以用有界整数解决。具体来说,对于整数A和整数位宽度的非空数组,我需要验证以下内容n

  1. 中的所有整数aA满足-2**(n-1) <= a < 2**(n-1)(用n-bit二进制数的补码整数表示)。
  2. 的长度A小于2**n
  3. A满足的总和-2**(n-1) <= sum(A) < 2**(n-1)
  4. 元素的所有组合均A满足所有上述条件。

自然,我决定将这个问题外包给您!

给定一个整数数组A和一个正整数位宽度n,请验证是否A满足上述条件。

测试用例

[0, 0, 0], 2: True
[0, 0, 0, 0], 2: False (violates #2)
[1, 2, 3, 4, 5], 8: True
[1, 2, 3, 4, 5], 2: False (violates all conditions)
[1, 2, 3, 4, 5], 5: True
[-3, 4, 1], 4: True
[10, 0, -10], 4: False (violates #1 and #4)
[27, -59, 20, 6, 10, 53, -21, 16], 8: False (violates #4)
[-34, 56, 41, -4, -14, -54, 30, 38], 16: True
[-38, -1, -11, 127, -35, -47, 28, 89, -8, -12, 77, 55, 75, 75, -80, -22], 7: False (violates #4)
[-123, -85, 6, 121, -5, 12, 52, 31, 64, 0, 6, 101, 128, -72, -123, 12], 12: True

参考实现(Python 3)

#!/usr/bin/env python3
from itertools import combinations
from ast import literal_eval


def check_sum(L, n):
  return -2**(n-1) <= sum(L) < 2**(n-1)


def check_len(L, n):
  return len(L) < 2**n


def check_elems(L, n):
  return all(-2**(n-1) <= a < 2**(n-1) for a in L)


A = literal_eval(input())
n = int(input())
OUTPUT_STR = "{}, {}: {}".format(A, n, "{}")

if not (check_elems(A, n) and check_len(A, n) and check_sum(A, n)):
  print(OUTPUT_STR.format(False))
  exit()

for k in range(1, len(A)):
  for b in combinations(A, k):
    if not check_sum(b, n):
      print(OUTPUT_STR.format(False))
      exit()

print(OUTPUT_STR.format(True))

在线尝试!



我们必须处理空清单吗?
Xcoder先生17年

@ Mr.Xcoder不,我会澄清。
Mego

Answers:


7

Wolfram语言(Mathematica),40个字节

Max[x=2Tr/@Subsets@#,-x-1,Tr[1^#]]<2^#2&

在线尝试!

通过检查所有子集(包括一元素子集)的条件3隐含条件1。因此,我们取最大

  • 每个子集之和的两倍
  • 小于每个子集的和的负数的两倍,并且
  • 整套的长度

并检查是否小于2^#2#2位宽输入在哪里)。

在只有6个字节的成本,我们可以更换Subsets@#使用GatherBy[#,Arg],这是更为有效,因为它仅计算两个最坏情况下的子集:所有非负值的子集,以及所有负值的子集。(之所以起作用,是因为前者和后者Arg的值都是。)0π


3

果冻,19字节

ŒPS€;⁸L¤ḟ⁹’2*$ŒRṖ¤Ṇ

在线尝试!

检查mapped sum of powerset + length of set是否在所需范围内就足够了。


1
认为(尽管我不确定)您可以使用ÆẸ而不是2*$(未
试用

@ Mr.Xcoder它的工作原理。
user202729 '17

3

05AB1E13 12 11字节

多亏了Xcoder先生,节省了1个字节

æO·D±¹gMIo‹

在线尝试!

说明

æ             # powerset of first input
 O            # sum each subset
  ·           # multiply each element by 2
   D          # duplicate
    ±         # bitwise negation of each element in the copy
     ¹g       # push length of first input
       M      # get the maximum value on the stack
        Io    # push 2**<second input>
          ‹   # compare

@ Mr.Xcoder:哦,是的,谢谢!(我一直忘了±
Emigna

2

JavaScript(ES6),75 63 58字节

a=>n=>!a.some(e=>(a.length|2*(e<0?l-=e:u+=e))>>n,u=0,l=-1)

任何a负数子集的总和都位于负数元素和非负数元素的总和之间,因此,除了情况2之外,检查所有两个总和就足够了。编辑:感谢@Arnauld,节省了12个 17字节。


比我幼稚的方法好得多。:-)可以缩短到61个字节
Arnauld

实际上,我们可以在循环中处理56个字节的测试。
Arnauld

在[[-2,-1,-2])(3)
l4m2

@ l4m2好收获。建议的修复方式(57个字节)
Arnauld

@Arnauld这里的问题是[-2, -2], 3应该是真的,不是吗?
尼尔,

1

果冻21 20字节

»0,«0$S€~2¦Ḥ;LṀ<2*Ɠ¤

在线尝试!

线性时间复杂度解决方案。原来我高估了时间的复杂性

在第19字节中,2017-12-11 13-15-03Z, by user202729

@NewSandboxedPosts“真实”子集总和问题要难得多。可以在线性时间完成此操作...

因为现在我意识到对数组进行排序完全没有必要了。


说明:

»0,«0$S€~2¦Ḥ;LṀ<2*Ɠ¤    Main link. Example list: [-1, 0, 1]
»0                      Maximize with 0. Get [0, 0, 1]
  ,                     Pair with
   «0$                    minimize with 0. Get [-1, 0, 0]
      S€                Sum €ach. Get [1, -1]
        ~               Inverse
          ¦               at element
         2                2. (list[2] = ~list[2]) Get [-1, 2]
           Ḥ            Unhalve (double, ×2). Get [-2, 4]
            ;           Concatenate with
             L            Length (3). Get [-2, 4, 3]
              Ṁ         Maximum of the list (4).
               <   ¤    Still less than
                2         two
                 *        raise to the power of
                  Ɠ       eval(input())


似乎~2¦可以;~。编辑:完成。
user202729

@ user202729错误。仍然;~$可以。
user202729

1

JavaScript(ES6),114个字节

以currying语法接受输入(A)(n)。返回一个布尔值。

A=>n=>!(A.reduce((a,x)=>[...a,...a.map(y=>[x,...y])],[[]]).some(a=>(s=eval(a.join`+`),s<0?~s:s)>>n-1)|A.length>>n)

测试用例



1

Clojure中,121个 117字节

#(let[l(int(Math/pow 2(dec %2)))](every?(set(range(- l)l))(cons(count %)(for[i(vals(group-by pos? %))](apply + i)))))

好吧,这有点愚蠢,将其分为正值和负值要比排序好得多。原始的,但令人惊讶的是,不再长:

#(let[l(int(Math/pow 2(dec %2)))S(sort %)R reductions](every?(set(range(- l)l))(concat[(count S)](R + S)(R +(into()S)))))

通过以升序和降序检查序列的前缀和来工作,我认为没有必要生成所有元素的组合 A

(into () S)实际上与相同(reverse S),因为列表从头开始增长。我想不出一种使用方法,cons而不是concat何时有两个列表cons。:/


1

果冻,15个字节

ŒPS€Ḥ;~$;LṀl2<Ɠ

在线尝试!

说明

ŒPS€Ḥ;~$;LṀl2<Ɠ ~ Monadic full program.

ŒP              ~ Powerset.
  S€            ~ The sum of each subset.
    Ḥ           ~ Double (element-wise).
     ;~$        ~ Append the list of their bitwise complements.
        ;L      ~ Append the length of the first input.
          Ṁ     ~ And get the maximum.
           l2   ~ Base-2 logarithm.
             <Ɠ ~ Is smaller than the second input (from stdin)?

多亏了aired coheringaahing(从STDIN而不是CLA读取第二个输入),节省了1个字节。


@ user202729我已经问过OP,我们不必处理空白列表
Xcoder先生17年

0

外壳,14个字节

≥Lḋ▲ṁ§eLöa→DΣṖ

通过遍历所有子列表进行暴力破解,因为拆分为正数和负数部分会占用更多字节。 在线尝试!

说明

≥Lḋ▲ṁ§eLöa→DΣṖ  Implicit inputs, say A=[1,2,3,4,5] and n=5
             Ṗ  Powerset of A: [[],[1],[2],[1,2],..,[1,2,3,4,5]]
    ṁ           Map and concatenate:
                  Argument: a sublist, say S=[1,3,4]
            Σ     Sum: 8
           D      Double: 16
          →       Increment: 17
        öa        Absolute value: 17
     §eL          Pair with length of S: [3,17]
                Result is [0,1,1,3,1,5,2,7,..,5,31]
   ▲            Maximum: 31
  ḋ             Convert to binary: [1,1,1,1,1]
 L              Length: 5
≥               Is it at most n: 1

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.