我的馅饼被平分了吗?


43

编写一个包含正整数的非空列表的程序或函数。您可能会假设它是以合理方便的格式输入的,例如"1 2 3 4"[1, 2, 3, 4]

输入列表中的数字表示完整饼图的切片,其中每个切片的大小与其对应的数字成比例,并且所有切片均按给定的顺序排列在图表周围。

例如,饼图为1 2 3 4

1 2 3 4例子

您的代码必须回答的问题是:饼图是否一分为二也就是说,从圆的一侧到另一侧是否存在一条完美的直线,将其对称地一分为二?

你需要输出truthy值,如果有至少一个平分线和输出falsy如果有没有价值

在该1 2 3 4示例中,之间有一个等分线4 12 3因此输出将是真实的。

但是对于输入而言1 2 3 4 5,没有平分线,因此输出将是虚假的:

1 2 3 4 5例子

其他例子

以其他方式排列数字可能会消除等分线。
例如2 1 3 4→虚假:

2 1 3 4例子

如果输入列表中只有一个数字,则饼图不会一分为二。
例如10→虚假:

10个例子

可能有多个平分线。只要大于零,输出就是真实的。
例如6 6 12 12 12 11 1 12→真实:(这里有3个等分线)

6 6 12 12 12 11 11 12示例

即使平分在视觉上不明显,也可能存在。
例如1000000 1000001→虚假:

1000000 1000001例子

例如1000000 1000001 1→真实:

1000000 1000001 1例子

(感谢nces.ed.gov生成饼图。)

测试用例

Truthy
1 2 3 4
6 6 12 12 12 11 1 12
1000000 1000001 1
1 2 3
1 1
42 42
1 17 9 13 2 7 3
3 1 2
10 20 10

Falsy
1 2 3 4 5
2 1 3 4
10
1000000 1000001
1
1 2
3 1 1
1 2 1 2 1 2
10 20 10 1

计分

以字节为单位的最短代码获胜。抢七是较早的答案。


30
我相信您是说要切馅饼吗?
Alex A.

@HelkaHomba,您可以重新排列扇区以使其正常工作吗,并且您所说的“以不同方式排列数字可能会消除平分线”?
所罗门·乌科2016年

@SolomonUcko您不能重新排列扇区。
加尔文的业余爱好

1
实际上,只有[2 1 3 4]个错误案例需要进行评估。其他虚假案例很容易被拒绝,因为它们的总和是奇数(或长度小于2)。
Benny Jobigan '16

Answers:


12

J,18个字节

5字节感谢丹尼斯。

+/e.[:,/2*+/\-/+/\

@HelkaHomba:不。

用法

>> f =: +/e.[:,/2*+/\-/+/\
>> f 6 6 12 12 12 11 1 12
<< 4
>> f 10 20 10 1
<< 0

不打高尔夫球

black_magic  =: +/\-/+/\
doubled_bm   =: 2 * black_magic
flatten      =: ,/
sum          =: +/
is_member_of =: e.
f =: sum is_member_of monadic flatten doubled_bm

以前的23字节版本:

[:+/[:+/+/=+:@-/~@(+/\)

用法

>> f =: [:+/[:+/+/=+:@-/~@(+/\)
>> f 6 6 12 12 12 11 1 12
<< 4
>> f 10 20 10 1
<< 0

不打高尔夫球

black_magic =: -/~@(+/\)
double      =: +:
equals      =: =
sum         =: +/
monadic     =: [:
of          =: @
f =: monadic sum monadic sum (sum equals double of black_magic)

说明

所有子字符串的总和由black_magic计算。的+/\计算中的部分和。

例如,a b c d变为a a+b a+b+c a+b+c+d

-/~随后构建了基于输入减法表,所以x y z就变成了:

x-x x-y x-z
y-x y-y y-z
z-x z-y z-z

当应用于时a a+b a+b+c a+b+c+d,结果将是:

    0  -b -b-c -b-c-d
    b   0   -c   -c-d
  b+c   c    0     -d
b+c+d c+d    d      0

这将计算不包含的所有子字符串的总和a

这保证了足够,因为如果一个等分包含a,则另一等分将不包含a也不会环绕。


3
通过一些重组,您可以获取13个字节:+/e.&,2*+/\\.
Zgarb

10

果冻9 8 字节

Ḥ+\©_Sf®

返回一个非空列表(真实)或一个空列表(虚假)。在线尝试!验证所有测试用例

这个怎么运作

Ḥ+\©_Sf®  Main link. Argument: A (list)

Ḥ         Double all integers in A.
 +\       Take the cumulative sum of 2A.
   ©      Copy; store the result in the register.
    _S    Subtract the sum of A from each partial sum of 2A.
      f®  Filter; intersect this list with the list in the register.

7

朱莉娅34 30 29字节

!x=sum(x)∈cumsum!(x,2x).-x'

感谢@GlenO打高尔夫球1个字节!

在线尝试!

这个怎么运作

存储的累积和后2XX,我们减去行矢量X”从列向量X,得到所有可能的差异矩阵。本质上,这将计算x的所有相邻子数组之和,这些子数组不包含第一个值,它们的负数和对角线中的0

最后,我们测试原始数组x的和是否属于生成的矩阵。在这种情况下,至少一个相邻子列表的总和等于整个列表总和的一半,这意味着至少有一个等分线。


15
让我们看一下,丹尼斯先给出5个答案,然后再给出其他答案。
加尔文的爱好

6

Python 2,64字节

f=lambda l,s=0:l>[]and(sum(l)==s)|f(l[1:],s+l[0])|f(l,s+l.pop())

递归尝试从最前面或最后删除元素,直到剩余的总和等于删除的总和为止,存储的总和为s。在列表长度中采用指数时间。

丹尼斯用节省了3个字节pop


给出列表的怪异选择:f=lambda l,s=0:l and(sum(l)==s)*l+f(l[1:],s+l[0])+f(l,s+l.pop())
xnor

5

Haskell,41个字节

f l=elem(sum l/2)$scanr(:)[]l>>=scanl(+)0

想法是检查是否存在一个子列表,l其总和等于sum l/2。我们将这些子列表的总和生成为scanr(:)[]l>>=scanl(+)0。让我们看看它如何与l=[1,2,3]

>> scanr(:)[]l
[[1,2,3],[2,3],[3],[]] 
-- the suffixes of l

>> scanl(+)0 [2,3,4]
[0,2,5,9]
-- the cumulative sums of the input

>> scanr(:)[]l>>=scanl(+)0
[0,1,3,6,0,2,5,0,3,0]
-- the cumulative sums of the suffixes of l, flattened to a single list

旧的43个字节:

f l|c<-scanl1(+)l=elem(sum l/2)$(-)<$>c<*>c

生成c累积总数列表。然后,sum l/2通过检查它是否是差异列表中的一个元素,来检查这些和中是否有两个是不同的(-)<$>c<*>c


4

Pyth,10个 9字节

}sQmysd.:

Pyth编译器中进行测试。

这个怎么运作

       .:  Generate the list of all adjacent sublists.
   m       Map over the result:
     sd       Add the integers of the sublist.
    y         Double the sum.
 sQ        Compute the sum of the input.
}          Check if it belongs to the list of doubled sublist sums.

4

其实是21个位元组

;Σ@2*;lR@τ╗`╜V♂Σi`Míu

在线尝试!

0对于错误的情况,此程序将打印出a;对于真实的情况,此程序将打印出正整数。

说明:

;Σ@2*;lR@τ╗`╜V♂Σi`Míu
;Σ                     sum of copy of input
  @2*                  double values in other copy
     ;lR               copy, range(1, len(input)+1)
        @τ             append other copy to itself
          ╗            save in reg0
           `╜V♂Σi`M    map: generate cyclic cumulative sums
                   íu  1-based index of sum of input (0 if not found)

非竞争版本,10字节

;Σ@2*σ;)-∩

在线尝试!

该程序输出虚假情况的空列表,否则输出非空列表。从本质上讲,它是丹尼斯的果冻答案的一部分。这是非竞争性的,因为累积总和和矢量化差异功能将挑战定为日期之后。

说明:

;Σ@2*σ;)-∩
;Σ          sum of copy of input
  @2*       multiply values in other copy by 2
     σ;     two copies of cumulative sum
       )-   subtract sum of input from each element in one copy
         ∩  set intersection with other copy

4

Python 2,76 74 70 66字节

def f(x):n=sum(x);print n in[2*sum(x[k/n:k%n])for k in range(n*n)]

感谢@xnor打高尔夫球4个 8字节!

Ideone上进行测试。(不包括较大的测试用例)


我意识到你可以n=sum(x)n in ...; 使用更大的值并不有害n
xnor

哦,那很聪明。谢谢!
丹尼斯

3

MATL,10字节

EYst!-Gs=z

输出为等分线数。

在线尝试!

说明

Dennis的Julia答案相同

E       % Implicit input. Multiply by 2 element-wise 
Ys      % Cumulative sum 
t!-     % Compute all pairwise differences. Gives a 2D array 
Gs      % Sum of input 
=       % Test for equality, element-wise 
z       % Number of nonzero elements. Implicit display 

3

红宝石, 60 53个字节

->a{a.any?{r=eval a*?+;a.rotate!.any?{|i|0==r-=2*i}}}

通过旋转输入数组的每一个旋转,然后获取长度为1的所有切片,生成所有可能的分区。n其中n,输入数组的大小。然后检查是否存在分区的总和等于输入数组总和的一半。


2

JavaScript(ES6),83个字节

a=>a.map(_=>a.slice(--n).map(m=>s.push(t+=m),t=0),s=[],n=a.length)&&s.includes(t/2)

生成所有可能的总和,然后检查是否有最后总和的一半(即整个列表的总和)出现在列表中。(以稍微尴尬的顺序生成总和以安排我需要最后保存的总和节省4个字节。)


2

Dyalog APL,12个字节

+/∊2×+\∘.-+\

TryAPL进行测试。

这个怎么运作

+/∊2×+\∘.-+\  Monadic function train. Right argument: y (vector)

     +\   +\  Yield the cumulative sum of y.
       ∘.-    Compute all differences of all partial sums.
              This computes the sums of all adjacent subvectors of y that do not
              contain the first value, their negatives, and 0's in the diagonal.
   2×         Multiply all differences by 2.
+/            Yield the sum of y.
  ∊           Test for membership.

2

Python 2,47个字节

k=t=1
for x in input():t<<=x;k|=t*t
print k&k/t

在线尝试!

我回来了2.75年后,使用新方法将我的旧解决方案击败了25%以上。

这个1字节长的版本更加清晰。

k=t=0
for x in input():t+=x;k|=4**t
print k&k>>t

在线尝试!

想法是将累积总和的集合存储t为的位k,设置该位2*t以指示这t是累积总和。然后,我们t通过将位数进行k很大的位移并&与原始位进行逐位运算以查看结果是否为非零(真实),来检查是否有两个累积总和与列表总和(最终)相差一半。


1

APL,25个字符

假定清单在中给出X ← 1 2 3 4

(+/X)∊∘.{2×+/⍺↑⍵↓X,X}⍨⍳⍴X←⎕

说明:

首先请注意,APL从右到左评估表格。然后:

  • X←⎕ 接受用户输入并将其存储在 X

  • ⍴X 给出长度 X

  • ⍳⍴X 从1到数字 ⍴X

  • {2×+/⍺↑⍵↓X,X}有左,右参数我们在大括号内定义一个二元函数。

    • 现在开始⍺↑⍵↓X,XX,X将X与自身连接;采取和下降。
    • +/缩小/折叠+在其右侧的列表上

    所以2 {2×+/⍺↑⍵↓X,X} 1= 2×+/2↑1↓X,X= 2×+/2↑1↓1 2 3 4 1 2 3 4=

    = 2×+/2↑2 3 4 1 2 3 4= 2×+/2 3= 2×5= 10

  • ∘.brace⍨idx就是idx ∘.brace idx。(是对角线图;∘.是外部乘积)

    所以这给了我们一个⍴X通过⍴X矩阵里面包含了所有连接子列表的两倍款项。

     4  6  8  2
    10 14 10  6
    18 16 14 12
    20 20 20 20
    

    我们要做的最后一件事是检查总和X是否在此矩阵内。

  • 与我们一起做(+/X)∊matrix


1

C,161个 145 129字节

  • @LeakyNun节省了几个字节
  • @ceilingcat节省了几个字节
i;j;k;t;r;s;f(x,n)int*x;{for(t=i=k=r=0;i<n;)t+=x[i++];for(;++k<n;i=n)for(;i--;r|=2*s==t)for(s=0,j=i;j<i+k;)s+=x[j++%n];return r;}

取消高尔夫 在线尝试

int f(int*x,int n)
{
    int t=0;

    for(int i=0;i<n;i++)
    {
        t += x[i];
    }

    for(int k=1;k<n;k++) // subset-size
    {
        for(int i=0,s;i<n;i++) // where to start
        {
            s=0;

            for(int j=i;j<i+k;j++) // sum the subset
            {
                s+=x[j%n];
            }

            if(2*s==t) return 1; // TRUE
        }
    }

    return 0; // FALSE
}

也许可以通过将变量的声明移到第一级并更改i<n;i++为来节省一些字节i++<n(尽管您可能需要处理一些偏移量。)
Leaky Nun

0

Haskell,68个字节

f l|x<-[0..length l]=any(sum l==)[2*(sum$take a$drop b l)|a<-x,b<-x]

该函数f首先创建一个给定列表的所有可能切片之和的列表。然后将其与列表元素的总和进行比较。如果我们在某个时候得到总和的一半,那么我们知道已经有一个二等分。我还使用这样的事实:如果您的元素takedrop列表中的元素个数超出列表,Haskell不会引发错误。


0

Mathematica,48个字节

!FreeQ[Outer[Plus,#,-#],Last@#/2]&@Accumulate@#&

匿名函数,其作用与众多其他答案类似。

Outer[Plus, #, -#],当进行操作时Accumulate@#(依次作用于输入列表,给出连续总数的列表),生成的表格基本上与Leaky Nun答案的底部相同。

!FreeQ[..., Last@#/2]检查结果表中(Last@#)/2是否存在,Last@#是否为连续总计的最后一个,即输入列表中所有元素的总和。

如果这个答案有些有趣,那不是因为有新算法,而是更多关于Mathematica的技巧。例如!FreeQ,与相比MemberQ,它很好,因为它不需要展平它检查的表保存一个字节。


我认为!FreeQ[2Tr/@Subsequences@#,Tr@#]&应该可以使用,但是在接下来的10天左右,我将无法使用10.4进行测试。
Martin Ender

@MartinEnder它看起来确实可以正常工作,但是我在10.2上,这就是我所拥有的
LLlAMnYP 2016年

0

APL(NARS),字符95,字节190

{1≥k←≢w←⍵:0⋄s←+/⍵⋄∨/{s=2×s-+/⍵}¨↑¨{⍵⊂w}¨{(k⍴2)⊤⍵}¨{1≥≢⍵:⍵⋄⍵,∇{(1+2×(↑⍵))×2*0..¯2+≢⍵}⍵}2*0..k-1}

考虑一个由4个元素组成的输入数组:1 2 3 4.我们如何选择对该集合的练习分区有用的数组?还有人认为我们可以使用的这4个元素的分区在左侧的二进制数中描述:

0001,0010,0100,1000 2^(0..4) 1 2 4  8 
0011,0110,1100,                3 6 12
0111,1110,                       7 14
1111                               15

(可能是1001或1011 ecc,但是已经有了0110和0100 ecc),所以只需要写一个函数,就可以从输入数组的元素数中构建这些二进制数...那就是:

c←{1≥≢⍵:⍵⋄⍵,∇{(1+2×(↑⍵))×2*0..¯2+≢⍵}⍵}

从输入1 2 4 8 [2 ^ 0..lenBytesArgument-1]得出3 6 12,7 14,15; 所以找到这些数字的二进制数并使用它们找到输入数组的正确分区...我仅针对输入的4个元素测试了c函数,但似乎对于其他数量的元素也可以...

测试:

  f←{1≥k←≢w←⍵:0⋄s←+/⍵⋄∨/{s=2×s-+/⍵}¨↑¨{⍵⊂w}¨{(k⍴2)⊤⍵}¨{1≥≢⍵:⍵⋄⍵,∇{(1+2×(↑⍵))×2*0..¯2+≢⍵}⍵}2*0..k-1}
  f¨(1 2 3 4)(6 6 12 12 12 11 1 12)(1000000 1000001 1)(1 2 3)(1 1)(42 42)
1 1 1 1 1 1 
  f¨(1 2 3 4 5)(2 1 3 4)(,10)(1000000 1000001)(,1)(1 2)(3 1 1)
0 0 0 0 0 0 0 
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.