矮人和硬币


32

情况:

几个M矮人发现了一个地精的箱子,上面放着N金币,必须将它们分开。由于古代规则控制着按优先级分配战利品给海盗,因此,最老的矮人应该比下一个最矮的矮人多获得一个硬币,依此类推,以便使最小的小矮人M-1比最老的矮人得到更少的硬币。另外,没有矮人必须投掷任何硬币(即,没有对任何矮人的负面硬币)

帮助矮人以这种方式分割硬币,或者告诉他们这是不可能的。

优胜者的代码必须始终正确回答(此挑战是确定性的),并遵循通用的规则。

输入值

硬币数的整数为N(3≤N≤1000),矮数的整数为M(3≤M≤N),以空格分隔。

输出量

如果无法按照矮人想要的方式分割硬币,则打印-1(减一)。否则,打印从最旧到最年轻的每个小矮人将获得的硬币数量。用空格分隔数字。

样品

输入

3 3

输出

2 1 0

输入

9 3

输出

4 3 2

输入

7 3

输出

-1

输入

6 4

输出

3 2 1 0

4
您错过了“海盗”。
罗林


3
好发现,@ Raystafarian。或许当老师指点对M一般求解矮人,而不是仅仅3中,他/她会认识到,用户众包的答案:) -特别是如果该解算器是在J.
ProgrammerDan

是否做作业,这是一个令人毛骨悚然的好问题!
水平河圣

Answers:


18

- 32 29 28 25

比其他J解决方案短 并使用了不同的想法

(]{.[:i:-:@-.@]-%)/ ::_1:

最高等级的gnome获得的硬币数量的答案很简单N/M+(M-1)/2(如果是整数),我们构造了this的负数-:@-.@]-%。然后为参数i:创建一个类似的数组,然后从中获取M个元素。2 1 0 _1 _2_2


1
+1的用法非常出色i:。您可以通过编写%而不是[%]和使用-.@]代替来保存另外三个字符(1-])
algorithmhark

@algorithmshark感谢J爱好者!
swish 2014年

1
无法+1,因为@swish似乎与我们刚才抢走的侏儒有关。;)
TheConstructor 2014年

11

J-30个字符

高尔夫很有趣。很多事情都巧妙地解决了。

((+/@s~i.[){ ::_1:s=.+/&i.&-)/

说明:

  • /-以空格分隔的整数作为参数,并在它们之间滑动函数。也就是说,将N放在括号中,(...)并将M 视为右边。

  • i.&--取反(-),然后取整数(i.)。通常,当您执行类似i.5get的操作时0 1 2 3 4i.但是,只要收到负数,它就会反转该输出列表。因此,例如i._5将给予4 3 2 1 0

  • s=.+/&-对每个参数(&)执行上述操作,然后+/从这些数组中制作一个加法表()。现在,我们有一个表格,其中每一行都是可能分配给M个矮人的硬币,尽管当有N个硬币时可能不是。最后,该制表动词非常有用,我们将对其进行调用s并在以后再次使用。

  • +/@s~-现在,我们s再次使用,但是我们交换(~)参数的顺序,以便对表进行转置。这是一种创建表(+/@)后获取每一行总和的方法,与J汇总多维列表的方式有关。

  • i.[ -在此总和列表中,我们搜索动词的左参数,即N。如果N是一个项目,则得到该索引:否则,我们得到列表的长度,这显然是无效的索引。

  • { ::_1:-现在我们尝试使用索引从中的表中提取一行s{如果索引无效,将抛出域错误,因此在这种情况下,我们捕获到错误(::)并返回-1(_1:)。这样处理一切。由于我们i.&-以前使用过,因此硬币分配将按照需要降序排列。

用法:

   ((+/@s~i.[){ ::_1:s=.+/&i.&-)/ 9 3
4 3 2
   ((+/@s~i.[){ ::_1:s=.+/&i.&-)/ 7 3
_1
   ((+/@s~i.[){ ::_1:s=.+/&i.&-)/ 6 4
3 2 1 0
   ((+/@s~i.[){ ::_1:s=.+/&i.&-)/ 204 17
20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4

输入9 3应该返回4 3 2,而不是-1。您的示例用法中似乎有换位吗?
ProgrammerDan

@ProgrammerDan谢谢,没有抓住。我把例子打错了。9 34 3 27 3_1,符合市场预期。
algorithmhark

看到修复程序并适当地+1:D。我应该看看J,很漂亮。
ProgrammerDan

7

R- 71 70 67 66 65个字符

s=scan();m=s[2];x=s[1]-sum(1:m);cat(if(x%%m|-m>x)-1 else x/m+m:1)

取消高尔夫:

s = scan()    # Reads N and M by stdin.
m = s[2]
x = s[1] - m*(m-1)/2
cat(if (x %% m | x < -m) -1 else x/m + m:1)

解:

如果M个小数的个数,那么有偿金的序列可以分解为两个奇异序列。首先以0结尾的序列:M-1,...,2,1,0和c,c,...,c的常数序列。第一个序列的总和始终为M *(M-1)/ 2。因此,如果可以将余数(x = N-M *(M-1)/ 2)除以余数(模等于0),则每个小数将得到x / M加上递减序列的一部分。

用法:

> s=scan()
1: 10 4
3: 
Read 2 items
> m=s[2]
> x = s[1] - m*(m-1)/2
> cat(if (x %% m || x<0) -1 else x/m + (m-1):0)
4 3 2 1

-1,问题要求编写一个完整的程序而不是一个函数。参见meta.codegolf.stackexchange.com/a/1146/8766
user80551'4

@ user80551你是对的。现在,我纠正了代码段:现在,它使用以空格分隔的输入。输出也不再显示“ [1]”。
lambruscoAcido

1
您可以保存其他字符替换m*(m+1)/2sum(1:m)
Brian Diggs 2014年

@Brian Thx,我将修改我的代码!
lambruscoAcido 2014年

4

PHP(187)

这是我第一次打高尔夫球,我知道这可能会更好,但仍然:)

打高尔夫球:

<?php
$b=fgets(STDIN);list($c,$d)=explode(' ',$b);if((($d&1)AND($c%$d==0))OR($c%$d==$d/2)){for($e=floor($c/$d)+floor($d/2);$e>floor($c/$d)-round($d/2);$e--){echo"$e ";}}else{die('-1');}?>

取消高尔夫:

<?php
$a = fgets(STDIN);
list($coins, $dwarves) = explode(' ', $a);
if ((($dwarves & 1) AND ($coins % $dwarves == 0)) OR ($coins % $dwarves == $dwarves / 2)) {
    for (
        $i = floor($coins / $dwarves) + floor($dwarves / 2);
        $i > floor($coins / $dwarves) - round($dwarves / 2);
        $i--
    ) {
        echo "$i ";
    }
}
else { 
  die('-1');
}
?>

在shell中执行

基本思路:

如果满足以下条件之一,则可以按以下规则分隔硬币:

  1. 矮人是奇数,硬币可以被矮人整除,没有残骸
  2. 矮人是偶数,除硬币/矮人后剩余的硬币等于矮人数的一半

如果是这样,我们以平均每个矮人硬币(ACPD)为基础。但是,我们必须从最高的开始,直到达到最低的输出。因此,我们以ACPD +矮人其余部分朝高端的计数开始,形成一个计数器循环,一直到ACPD-矮人其余部分朝低端的计数开始。

如果矮人是奇数,则基本上是相同的(即5个矮人-中间是3个,两端都剩下2个),但即使它们是偶数也不是-这就是为什么我们依靠底数和回合。

到目前为止存在的问题: 硬币数量太少时工作,这意味着一些矮人将被击sm并抢走其宝贵的收入。这真可悲。或者至少如果您喜欢矮人。

解决方案

  1. 考虑一种计算最低数量的硬币的方法,这样计算就不会因尘土飞扬而告终。
  2. 设计不太贪婪的小矮人。

更智能的解决方案

硬币是金属。使矮人将它们全部融化,然后将它们浇入较小/较大数量的硬币中,以便在任何情况下都可以将它们整除。

最聪明的解决方案

偷走他们的山峰,将自己重命名为史矛革,并全力以赴。毕竟,您为什么要烦恼脾气暴躁的矮人?


4

的Python 3(100)

使用与@Geobits相同的想法,但符合输入和输出要求。

n,m=map(int,input().split())
κ,ρ=divmod(n-m*(m-1)//2,m)
x=[-1]if ρ else range(κ,κ+m)[::-1]
print(*x)

感谢您的单挑。没有注意到添加到输入请求中的空格。
Geobits

这些可能是100个字符,但是由于希腊变量名称的原因,它需要105个字节。
乔纳森·弗雷希

4

Python的3 - 109 107 103 102 90 93

使用与Evpok相同的构想,但进行了许多改进。

n,m=map(int,input().split())
k=n/m+m/2
a=int(k)
print(*(range(a,a-m,-1),[-1])[k-a-.5or~a>-m])

改进之处包括:

  1. 消除在“”之后的空间。1个字符
  2. 删除split()内的'',因为默认情况下是在空格处分割。3个字符
  3. 将x减1可以将divmod中的-1更改为+1,然后更改range函数以使用范围的逆序选项。3个字符。
  4. 编辑:...如果...否则...更改为...和...或... 2个字符。
  5. 编辑:Divmod明确,r删除。4个字符。
  6. 编辑:x删除,m // n明确使用。1个字符
  7. 编辑:使用加星号的表达式而不是''.join(map(str,...)),添加了x以避免重复print()。12个字符。
  8. 编辑:我意识到我正在允许负数的硬币给矮人。我更改了代码以避免这种情况。

做得好,这很有启发性:)我更改了答案以去除不必要的空间,但是保存该[::-1]方法的窍门比我的解决方案要好。+1
Evpok

我可能失去了一些东西,但是我算93个字节,而不是94
乔纳森富来

3

Python 3-114

n,m=map(int,input().split(' '))
r=range(m);n-=sum(r)
if n%m<1:
 for x in r:print(m-x+n//m-1,end=' ')
else:print -1

通过检查是否可N-(M*(M-1)/2)被整除来工作M。是python的新手,因此感谢所有提示。

Ideone.com示例

Input:
735 30
Output:
39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10

是否有支持Python 2 print语句风格的Python 3版本?或最后一行(else:print -1)如何不会导致错误?
乔纳森·弗雷希

3

C#-322

using System;using System.Linq;namespace D{class P{static void Main(string[]args){int n=Convert.ToInt16(args[0]);int m=Convert.ToInt16(args[1]);bool b=false;int q=n/2+1;g:b=!b;int[]z=new int[m];for(int i=0;i<m;i++){z[i]=q-i;}if(z.Sum()==n)foreach(int p in z)Console.Write(p+" ");else{q--;if(b)goto g;Console.Write(-1);}}}}

糟糕的分数,但我采用了不同的方法并开始使用 goto :)

我将在稍后将其缩短。


1
您绝对可以将所有这些Convert.ToInt16呼叫缩短为just int.Parse。您可以使用var(而不是例如int[])声明任何预分配的变量。您不需要调用命令行参数args。您也可以为常用类型加上别名using C = Console。我还认为,对于这样长的解决方案,最好保留完整的行距,而不是只保存几个字符。哦,我也不太确定为什么goto要比这里的替代方法好……
Aaronaught

3

Java 210

class A { public static void main(String[] a){int d=Integer.parseInt(a[0]),c=Integer.parseInt(a[1]);if (2*c%d==0) for (int i=0;i<d;i++) System.out.print((((1+(2*c/d)-d)/2)+i)+" "); else System.out.print(-1);}}

2
欢迎使用PPCG,我看到您有很多可以删除的空白。
pastebin.com斜线0mr8spkT 2014年

您可以腾出更多空间来进一步解答问题-例如,class A{public static void main(String[]a)有效,可以节省3个字符。在每个if之后以及每个周围for,删除空格...等
ProgrammerDan

疯狂的是,“ public static void main(S)部分与整个J解一样长:)
Robert Grant

3

R:77 73 70个字符

a=scan();r=a[2]:1-1;while((n=sum(r))<a[1])r=r+1;cat(`if`(n>a[1],-1,r))

创建一个从(M-1)到0的向量,并向每个数字加1,直到总和不再低于N。如果该和大于,则输出-1,否则输出向量。

缩进和略微松开:

a=scan()   #Reads in stdin (by default numeric, space-separated)
r=a[2]:1-1 #Creates vector (M-1) to 0
while(sum(r)<a[1])r=r+1 #Increments all member of vector by 1 until sum is not inferior to N
cat( #Outputs to stdout
    `if`(sum(r)>a[1], -1, r) #If superior to N: impossible, returns -1
    )

用法示例:

> a=scan();r=a[2]:1-1;while((n=sum(r))<a[1])r=r+1;cat(`if`(n>a[1],-1,r))
1: 9 3
3: 
Read 2 items
4 3 2
> a=scan();r=a[2]:1-1;while((n=sum(r))<a[1])r=r+1;cat(`if`(n>a[1],-1,r))
1: 7 3
3: 
Read 2 items
-1
> a=scan();r=a[2]:1-1;while((n=sum(r))<a[1])r=r+1;cat(`if`(n>a[1],-1,r))
1: 204 17
3: 
Read 2 items
20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4

2

朱莉娅45岁

f(n,m)=(x=n/m-m/2+1/2;x%1==0?[x+m-1:-1:x]:-1)
julia> f(6,4)'
1x4 Array{Float64,2}:
 3.0  2.0  1.0  0.0

只是一点代数,就花了我更长的时间。


2

JavaScript-76

观察到k +(k-1)+ ... +(k-(M-1))= M(k-(M-1)/ 2)将此值设置为N可得出k = N / M +(M -1)/ 2为最高金额。如果这是整数,则k%1 == 0,我们要寻找的数量是k,k-1,...,k-(M-1)。

我本可以用另一种语言写得短一些,但是还没有JS解决方案,所以这里是:

N=3;M=3;if((r=N/M+(M-1)/2)%1)console.log(-1);else while(M--)console.log(r--)

在控制台中运行。

输入示例:

N=3;M=3;if((r=N/M+(M-1)/2)%1)console.log(-1);else while(M--)console.log(r--)

输出:

3
2
1 

输入:

N=6;M=4;if((r=N/M+(M-1)/2)%1)console.log(-1);else while(M--)console.log(r--)

输出:

3
2
1
0

输入:

N=7;M=3;if((r=N/M+(M-1)/2)%1)console.log(-1);else while(M--)console.log(r--)

输出:-1

太糟糕的console.log拼写太久了:)不幸的是,声明l=console.log.bind(console)并没有使其变得更短,而且l=console.log根本行不通。

输入:

"N=3;M=3;if((r=N/M+(M-1)/2)%1)console.log(-1);else while(M--)console.log(r--)".length

输出:

76

您可以使用c=consolec.log()缩短它。
user2428118 2014年

2

Golfscript,35岁

~:M.(*2/-.M%{;-1}{M/M+,-1%M<' '*}if

怎么运行的

在以下示例中,输入为9 3

          # STACK: "9 3"
~         # Interpret the input string.
          # STACK: 9 3
:M        # Store the top of the stack (number of dwarves) in variable `M'.
.         # Duplicate the top of the stack.
          # STACK: 9 3 3
(         # Decrement the top of the stack.
          # STACK: 9 3 2
*         # Multiply the topmost elements of the stack.
          # STACK: 9 6
2/        # Divide the top of the stack by `2'.
          # STACK: 9 3
          # So far, we've transformed `M' into `M*(M-1)/2', which is the minimum amount of
          # coins all dwarves together will get. This number comes from the fact that the
          # youngest dwarf will get at least 0 coins, the next at least 1 coin, etc., and
          # 0 + 1 + ... + (M - 1) = M*(M-1)/2.
-         # Subtract the topmost elements of the stack.
          # STACK: 6
          # The remaining coins have to get reparted evenly to all dwarves.
.         # Duplicate the top of the stack.
          # STACK: 6 6
M%        # Calculate the top of the stack modulus `M'.
          # STACK: 6 0
{         # If the modulus is positive, the remaining coins cannot get reparted evenly.
    ;-1   # Replace the top of the stack by `-1'.
}
{         # If the modulus is zero, the remaining coins can get reparted evenly.
    M/    # Divide the top of the stack by `M'.
          # STACK: 2
          # This is the number of coins all dwarves will get after giving 1 to the second
          # youngest, etc.
    M+    # Add `M' to the top of the stack.
          # STACK: 5
    ,     # Replace the top of the stack by an array of that many elements.
          # STACK: [ 0 1 2 3 4 ]
          # The rightmost element is the number of coins the oldest dwarf will get.
    -1%   # Reverse the array.
          # STACK: [ 4 3 2 1 0 ]
    M<    # Keep the leftmost `M' elements.
          # STACK: [ 4 3 2 ]
          # There are only `M' dwarves.
    ' '*  # Join the array, separating by spaces.
          # STACK: "4 3 2"
}if

1

德尔福XE3(176)

uses SysUtils;var d,c,i:integer;begin read(c,d);for I:=1to d-1do c:=c-i;if c mod d>0then writeln(-1)else begin c:=c div d;for I:=d-1downto 0do write(IntToStr(i+c)+' ');end;end.

怎么运行的。

读取2个整数,硬币和矮人。
减去每个小矮人的差。
如果余数mod矮> 0,则不可能。
否则,在矮人-1到0的循环中,每个矮人获得相等的份额,并输出dwarfIndex + equal share

不打高尔夫球

uses SysUtils;
var
  d,c,i:integer;
begin
  read(c,d);
  for I:=1to d-1do
    c:=c-i;
  if c mod d>0then
    writeln(-1)
  else
  begin
    c:=c div d;
    for I:=d-1downto 0do
      write(IntToStr(i+c)+' ');
  end;
end.

1

Mathematica 65

函数g生成所有长度为m的从0到n的加一序列,并检查它们中的任何一个是否等于m。如果成功,则返回序列。否则,返回-1。

的序列通过由Partition荷兰国际集团的列表{0,1,2,3 ...}米成n个连续整数的所有可能的子列表。

当然,有更有效的方法可以达到相同的效果,但是我发现的方法需要更多的代码。

n_~g~m_:=If[(s=Select[Partition[0~Range~n,m,1],Tr@#==n&])=={},-1,s]

例子

g[9, 3]

{{2,3,4}}


g[3, 3]

{{0,1,2}}


g[7, 3]

-1


g[705, 3]

{{234,235,236}}


g[840, 16]

{{45、46、47、48、49、50、51、52、53、54、55、56、57、58、59、60}}


g[839, 16]

-1


1

C 131

#include <edk.h>
main(int a,char **v){int j=atoi(*++v),k=atoi(*++v)-j*(j-1)/2;k<0||k%j?j=1,k=-1:k/=j;while(j--)printf("%d ",k+j);}

不打高尔夫球

#include <edk.h> //Shortest standard header including stdio.h and stdlib.h
main(int a,char **v)
{
    int j=atoi(*++v),k=atoi(*++v)-j*(j-1)/2;

    k<0||k%j?j=1,k=-1:k/=j;  // If youngest dwarf gets < 0 or amount not equally divisible then set values such that ...

    while(j--)printf("%d ",k+j); // ... loop prints out correct values
}

由于main没有类型,因此会编译警告。如果这在高尔夫规则中无效,我将不得不添加五个字符。


1

眼镜蛇-198

眼镜蛇网站

class P
    def main
        x,y=Console.readLine.split
        a,b=x to int,y to int
        l=[]
        t=n=0
        for i in b,t+=i
        while (t+=b)<=a,n+=1
        for i in b,l.insert(0,i+n)
        print if(t-b<>a,-1,l.join(" "))

解释:

class P
    def main

代码运行所必需

        x,y=Console.readLine.split
        a,b=x to int,y to int

接受输入,并将其存储ab

        l=[]
        t=n=0

初始化输出列表l,并初始化所需的总金钱t和要添加到每个矮人堆中的硬币数量n

        for i in b,t+=i

查找将导致所有矮人的硬币堆中允许数量的最低货币价值

        while (t+=b)<=a,n+=1

确定要添加到每堆中的硬币数量,以使所需的总金额大于可用总金额

        for i in b,l.insert(0,i+n)

用不同大小的钱堆满列表

        print if(t-b<>a,-1,l.join(" "))

输出-1l取决于所需的总金额是否等于可用的总金额



-1

Python(100 96 94):

一个不错的,满分的答案。不再,但是现在更短了。

def f(n,m):a=range(m)[::-1];b=n-sum(a);c=b/m;d=[i+c for i in a];return(d,-1)[-1in d or c*m!=b]

取消高尔夫:

def f(n,m):
 a = range(m)[::-1]
 b = sum(a)
 c = (n-b)/m
 if c * m != n-b: return -1
 d = [i+c for i in a]
 return (d,-1)[-1 in d or c!=n-b]
 if -d in d or c*m!=n-b:
  return -1
 return d

输出:

def f(n,m):a=range(m)[::-1];b=sum(a);c=(n-b)/m;d=[i+c for i in a];return (d,-1)[-1 in d or c*m!=n-b]

f(3,3)
Out[2]: [2, 1, 0]

f(9,3)
Out[3]: [4, 3, 2]

f(7,3)
Out[4]: -1

f(6,4)
Out[5]: [3, 2, 1, 0]

2
这不符合输入要求。
奥斯汀·亨利

-1,问题要求编写一个完整的程序而不是一个函数。参见meta.codegolf.stackexchange.com/a/1146/8766
user80551'4
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.