你会打高尔夫球吗?


53

您需要生成一个随机的18洞高尔夫球场。

输出示例:

[3 4 3 5 5 4 4 4 5 3 3 4 4 3 4 5 5 4]

规则:

  • 您的程序必须输出正好18个孔的孔长度列表
  • 每个孔的长度必须为3、4或5
  • 整个过程中,孔长总计必须为72
  • 您的程序必须能够产生具有某些非零概率的每个可能的孔配置(每个配置的概率不必相等,但是在这种情况下,可以随时要求额外的荣誉)

3
请确认44152809解决方案?
baby-rabbit

1
我也对解决方案的确切数量感到好奇,但是我认为应该超过4400万……(我不是数学家,但是:| 1(5)/ 1(3)= 306种可能性(17 * 18) | 2(5)/ 2(3)= 69360个位置(17 * 17 * 16 * 15)| 3(5)/ 3(3)= 11182080个位置(16 * 16 * 16 * 15 * 14 * 13)|看起来合适吗?
NRGdallas 2012年

11
@ baby-rabbit:我可以通过蛮力枚举来确认44,152,809个解决方案。此外,它可以直接计算是这样的:因为平均恰好4,唯一的可能性34或者5,可能的解决方案类{ no 3's or 5'sone 3 and one 5two 3's and two 5's,... nine 3's and nine 5's}。可以通过计算nCr(18,0)*nCr(18,0) + nCr(18,1)*nCr(17,1) + nCr(18,2)*nCr(16,2) + ... + nCr(18,9)*nCr(9,9) = 44,152,809。这意味着大约11.4%所有可能的组合都是有效的解决方案(44,152,809 / 3^18)
mellamokb 2012年

2
sum(factorial(18)/factorial(x)/factorial(y)/factorial(z) for x in range(25) for y in range(25) for z in range(25) if 3*x+4*y+5*z == 72 and x+y+z == 18)44152809L
Sanjeev Murty 2014年

Answers:


29

k(18 17 16个字符)

回到原始的方法,归功于CS的改进。

(+/4-){3+18?3}/0

其他方法(17个字符),与J解决方案相同的方法,从H / T到CS

4+a,-a:9?2 -18?18

旧版本:

(72-+/){18?3+!3}/0

不易受堆栈溢出的影响,并在固定的空间中运行。


什么是CS的H / T?
Gareth 2012年


该程序帮助我发现我的K解释器中的错误-谢谢!我以前没有意识到,尼拉德人可以应用于一个论点(他们忽略了)。
JohnE


15

J,20 18 17个字符

(?~18){4+(,-)?9#2

除9个随机数字为0或1且在附加之前被取反外,这与上一个答案的工作方式相同。这意味着-1s与1s 一样多。加4给我一个3s,4s和5s 的列表,每次的总和为72。

先前的答案:

({~?~@#)3+(,2-])?9#3

随机生成前9个孔?9#3,然后将其复制并反转(,2-])(将3变成5,将5变成3)以生成最后9个孔。这样可以保证总数为72(因为每3个孔都具有匹配的5个孔)每个孔的平均总数为4和4x18 = 72)。然后,它会随机调整结果({~?~@#)以确保每种组合都是可能的。


实际上,您不会生成{3,5,4,4,4 ...},因此最好改组整个结果
棘手的

@rachetfreak好点。我现在编辑。
Gareth 2012年

13

MS-DOS下的16位x86机器代码-45字节

十六进制转储:

0E5F576A12595188ECE44088C3E44130D8240374F400C4AAE2EF595E80FC2475DFAC0432CD29B020CD29E2F5C3

Base64编码的二进制文件:

Dl9XahJZUYjs5ECIw+RBMNgkA3T0AMSq4u9ZXoD8JHXfrAQyzSmwIM0p4vXD

实际的源代码并带有一些注释:

 bits 16
 org 0x100

again:
 push cs               ; Save whatever CS we get.
 pop di                ; Use CS:DI as our course buffer..
 push di               ; Save for later use in the print loop
 push 18               ; We need 18 holes for our golf course.
 pop cx                ; ch = 0, cl = 18.
 push cx               ; Save for later use.
 mov ah, ch            ; Zero out ah.
generate_course:
 in al, 0x40           ; Port 0x40 is the 8253 PIT Counter 0.
 mov bl, al            ; Save the first "random" value in bl.
 in al, 0x41           ; Port 0x41 is the 8253 PIT Counter 1.
 xor al, bl            ; Add some more pseudo randomness.
 and al, 3             ; We only need the two lower bits.
 jz generate_course    ; If zero, re-generate a value, since we need only 3, 4, 5 holes.
 add ah, al            ; Sum in ah register.
 stosb                 ; Store in the course buffer.
 loop generate_course  ; Loop for 18 holes.
 pop cx                ; cx = 18.
 pop si                ; si = course buffer.
 cmp ah, 36            ; 72 holes?
 jne again             ; No, re-generate the whole course.

print:                 ; Yup, we have a nice course.
 lodsb                 ; Load the next hole.
 add al, '2'           ; Add ASCII '2' to get '3', '4' or '5'
 int 0x29              ; Undocumented MS-DOS print function.
 mov al, ' '           ; Print a space too for better readability.
 int 0x29              ; Print the character.
 loop print            ; Print the whole course.
 ret                   ; Return to the beginning of the PSP where a INT 0x20 happen to be.

使用nasm 18h.asm -o 18h.com32位Windows版本的MS-DOS(或Dosbox)或NTVDM进行编译并在其中运行。

样本输出:

4 5 4 5 4 5 3 4 3 4 3 4 4 5 4 3 5 3

3
爱汇编者...
woliveirajr 2012年

13

Mathematica 71 68 66 60

通过Tally的建议保存了6个字符。

RandomSample@RandomChoice@IntegerPartitions[72, {18}, {3, 4, 5}]

{5、4、3、3、5、3、5、5、3、3、4、5、3、5、4、4、5、3}

所有可能的结果都是可能的,但可能性并不相同。


分析

IntegerPartitions[72, {18}, {3, 4, 5}]

将72的所有10个可能的分区(组合,而不是置换)生成为18个由3、4和5组成的元素。

隔断


RandomChoice 选择其中之一。

RandomSample 返回该选择的排列。


呵呵,我正要发布几乎完全相同的答案,只是使用RandomChoice而不是RandomInteger。我认为您可以再剃4个字符。
Tally 2014年

理货,谢谢。您的建议很有帮助。
DavidC 2014年

8

R-41

x=0;while(sum(x)!=72)x=sample(3:5,18,T);x

# [1] 5 3 5 3 3 3 3 3 5 4 5 4 5 4 4 5 5 3

该算法类似于@sgrieve的算法。


与上面的@sgrieve相同的问题-没有什么可以阻止它在18个孔中翻倒的。
gt6989b 2012年

3
没问题,在这种情况下,sample命令始终生成18个值。
悲痛

8

GolfScript(26个字符)

{;0{3rand.3+@@+(}18*])}do`

与Ilmari的解决方案有一些明显的相似之处,但也有一些明显的差异。特别是,我正在利用平均票数为4的事实。


该死的,但是那肯定是那里的循环条件的一个巧妙窍门。我想出了 {;0{3.rand+.@+}18*])72-}do自己的想法,但不知道如何从那里缩短时间。+1。
Ilmari Karonen 2012年

7

Python 77

from numpy.random import*;l=[]
while sum(l)!=72:l=randint(3,6,18)
print l

输出量

[3 4 4 5 3 3 3 5 4 4 5 4 5 3 4 4 5 4]

导入确实杀死了该解决方案。它使用numpy生成3到5之间的18个数字,并不断生成列表,直到列表的总和等于72。


是什么导致程序无法在生成18个孔之前达到72孔?是什么阻止它跳过72?
DavidC 2012年

3
该代码将始终生成18个孔,然后检查总和是否等于72。例如,如果16个孔之后的总和为72,它仍将再生成2个孔,从而将总和推到72以上并通过测试。
2012年


7

Q(25个字符)

原创(27)

while[72<>sum a:18?3 4 5];a

样品输出

4 4 3 3 4 5 4 3 4 5 5 3 5 5 5 4 3 3

稍短(25)

{72<>sum x}{x:18?3 4 5}/0

7

JavaScript,66 64 61个字符

受TwoScoopsofPig(PHP)和Joe Tuskan(JS)的启发。

for(a=[s=0];s!=72;)for(s=i=0;i<18;s+=a[i++]=Math.random()*3+3|0);a

for(a=[s=0];s-72;)for(s=i=0;i<18;s+=a[i++]=Math.random()*3+3|0)a

for(a=s=[];s;)for(i=18,s=72;i;s-=a[--i]=Math.random()*3+3|0)a

2
s!=72可以是s-72保存一个字符。而且;a,另一个字符也不需要最后一个分号。
Joe Tuskan 2012年

我从未见过for(i=x;i;i--),它可以节省2个字符for(i=0;i<x;i++),谢谢!
数学冷却器

7

Python 2,70个字节

from random import*
print sample(([3,5]*randint(0,9)+[4]*99)[:18],18)
编辑:

这是另一个,类似于悲伤的解决方案:

Python 2,73字节+相等的概率

from random import*
a=[]
while sum(a)-72:a=sample([3,4,5]*18,18)
print a

5

JavaScript,116 99 65字节

for(i=0,h=[];i<18;)h[i++]=5;while(h.reduce(function(a,b){return a+b})!=72){i=Math.random()*18|0;h[i]=[3,4,4][i%3]}h;

h=[0];while(h.reduce(function(a,b){return a+b})-72)for(i=0;i<18;h[i++]=[3,4,5][Math.random()*3|0])h

while(i%18||(a=[i=s=0]),s+=a[i++]=Math.random()*3+3|0,s-72|i-18)a

1
当我在Chrome 21中运行此代码时,我得到了i is not defined
mellamokb 2012年

5

Python,128120116 字符

import random,itertools
random.choice([g for g in itertools.product(*(range(3,6)for l in range(18))) if sum(g)==72])

import 语句仍然是长度杀手(23个字符只能在名称空间中导入2个函数)

我希望您在不久的将来不需要结果,因为此代码首先评估所有可能的解决方案,然后再随机选择一个。也许是解决这个问题最慢的方法。

我确实为每种配置的均等概率要求额外的荣誉...


4
import random,itertools
grawity 2012年

您是对的,这会使事情缩短一点。
Adrien Plisson

其他提示:import random as r,itertools as i然后使用ri代替randomitertools。使用18*[0]代替range(18)[3,4,5,6]代替range(3,6):)
Alex L

我正在使用python 3:列表推导是一个生成器,并且没有长度,因此禁止将其与choice()函数一起使用。这也是使此代码如此缓慢的原因...
Adrien Plisson 2012年

1
糟糕,抱歉,我搞砸了列表理解和生成器表达式(由于迭代器更好的性能,我通常避免使用列表表达式来支持生成器表达式)。所以的确,即使在python3中,我仍然可以删除一些字符... @Alex做得对。
Adrien Plisson 2012年

4

PHP-77个字符

<?while(array_sum($a)!=72){for($i=0;18>$i;){$a[++$i]=rand(3,5);}}print_r($a);

就像sgrieve的解决方案一样,它构建了一个18洞的列表,检查总面值,然后打印或拒绝它,然后重试。奇怪的是,我们两个解决方案的长度相同。

令人讨厌的是,PHP不提供名称简短的数组函数。Array_sum和print_r杀死了我。欢迎提出建议。


1
这里不需要花括号,总和可以是+=<?while($s!=72)for($s=$i=0;18>$i;$s+=$a[++$i]=rand(3,5));print_r($a);
grawity 2012年

这很有用-我从没想过要把逻辑放在 for循环调用中(而且我不为总和增加计数器感到有点傻)。
TwoScoopsofPig 2012年

谢谢–但这实际上并不是我所谓的“不需要花括号”;您也可以在原始代码中将其删除:while(array_sum($a)!=72)for($i=0;18>$i;)$a[++$i]=rand(3,5);
grawity 2012年

好吧,除了我在比上面更严格的php.ini上运行外,因为我在打高尔夫球。它抱怨牙套丢失/不匹配没有尽头。通常我会的。
TwoScoopsofPig 2012年

奇怪 使用E_ALL | E_STRICT的5.4.7永远不会抱怨缺少{}(因为PHP的语法明确允许这样做)。
grawity 2012年

4

Ruby 1.9(62个字符)

a=Array.new(18){[3,4,5].sample}until(a||[]).inject(:+)==72
p a

Rails(55个字符)

$ rails cREPL中(在任何Rails文件夹中):

a=Array.new(18){[3,4,5].sample}until(a||[]).sum==72
p a

注意:如果您使用shuffle[0]而不是,它将与Ruby 1.8一起使用sample


2
直到您需要空格吗?
卡兹(Kaz)2012年

@Kaz你是对的,不需要。:)现在有62个字符。
js-coder

1
您可以(1..18).map{rand(3)+3}用来获取随机数组;)
流行病学

4

Lisp(78 69个字符)

(((c()(mapcar(lambda(x)(+ 3(随机3)))(make-list 18))))(((=(apply'+ c)72)c))

(do((c()(loop repeat 18 collect(+ 3(random 3)))))((=(apply'+ c)72)c))

它与sgrieve的Python解决方案非常相似。

从c开头为NIL,检查总和为72,doc 的“增量函数”生成一个介于3和5之间的18个数字的列表,再次检查72,进行起泡,冲洗,重复。

很高兴看到doloop一起打高尔夫球。


3

C(123个字符)-努力提高效率

通过wc进行管道传输,它将在10秒内生成所有44152809解决方案。

char s[19];g(d,t){int i;if(d--){for(i=51,t-=3;i<54;i++,t--)if(t>=3*d&&t<=5*d)s[d]=i,g(d,t);}else puts(s);}main(){g(18,72);}

哦,嗯-没有正确地阅读问题-但是鉴于我们正在生成所有解决方案,然后以相等的概率选择一个随机的解决方案是一项脚本练习:P


3

Clojure-55

(shuffle(mapcat #([[4 4][3 5]%](rand-int 2))(range 9)))

相当有趣。...利用了问题的数学结构,即3个标准孔必须与5个标准孔一样多。


3

Python 83

import random as r;x=[]
while sum(x)!=72:x=[r.randint(3,5) for i in 18*[0]]
print x

像sgrieve的解决方案,但没有numpy

高尔夫Adrien Plisson的解决方案: 120-> 108个字符

import random as r,itertools as i
r.choice([g for g in i.product(*([3,4,5,6]for l in 18*[0]))if sum(g)==72])

MATLAB 53

x=[];
while sum(x)~=72
x=3+floor(rand(1,18)*3);
end
x

输出

x = 4 3 4 4 4 4 5 4 4 3 4 4 3 5 3 5 4 5


不错的方法,但是您可以通过键入randi([3,5],1,18)代替4个字节来节省4个字节3+floor(rand(1,18)*3)
brainkz 2016年

3

Java(61个字符)

while(s!=72)for(i=0,s=0;i<18;i++)s+=3+(int)(Math.random()*3);

样本输出:

5 4 3 4 5 3 4 4 3 5 4 4 4 4 3 4 4 5

我不是Java专家,但是不应该有s和i的声明以及对System#println(..)的某种调用吗?
hiergiltdiestfu

这只是一个代码片段,而不是程序。实际上,它看起来非常类似于@JoeIbanez的C版本。
Franz D.

2

C(94个字符)

int h[18],s=0,i;
while(s!=72)for(i=s=0;i<18;s+=h[i++]=rand()%3+3);
while(i)printf("%d ",h[--i]);

s=0第1行可以不需要,因为什么是机会一个未初始化的INT将等于72?我只是不喜欢在直接C语言中读取未初始化的值。而且,这可能需要为rand()函数植入种子。

输出

3 3 3 4 5 5 3 3 4 5 5 4 3 4 5 5 5 3 

因此,基本上,您将循环遍历3至5的18个数字的随机字符串,直到一个正好等于72?好东西效率不是必需的。
KeithS 2012年

5
@KeithS公平地说,这就是该问题的大多数答案。
Gareth 2012年

2

Bash Shell脚本(65个字符)

shuf -e `for x in {0..8}
do echo $((r=RANDOM%3+3)) $((8-r))
done`

shuf来自GNU coreutils软件包。此外,感谢Gareth。)


2

C#(143个非空白):

()=>{
  var n=new Math.Random().Next(10);
  Enumerable.Range(1,18)
    .Select((x,i)=>i<n?3:i>=18-n?5:4)
    .OrderBy(x=>Guid.NewGuid())
    .ForEach(Console.Write);
}

new Guid()创建一个空的GUID。要实际生成唯一的GUID,您需要调用静态方法Guid.NewGuid
Rotsor 2012年

并且有两个非一对一的错误(可以这么说):比较应该是i <n和i> = 18-n,而不是相反。您可以通过使用常量3而不是x-1和5而不是x + 1来减小大小。然后您可以将Enumerable.Repeat替换为Enumerable.Range。
Mormegil 2012年

编辑; 还是143个字符
KeithS

没有Math.Random,是System.Random
CodesInChaos

另一种C#方法(143个字符):var r=new Random();for(;;){var e=Enumerable.Range(1,18).Select(i=>r.Next(3,6)).ToList();if(e.Sum()==72){e.ForEach(i=>Console.Write(i));break;}}
thepirat000 2014年

2

Haskell,104 102 98个字符。

import System.Random
q l|sum l==72=print l|1>0=main
main=mapM(\_->randomRIO(3::Int,5))[1..18]>>=q

[1..n]>>[r]比略短replicate n$r
停止转动逆时针

也更改sequencemapM
Rotsor 2012年

2

Perl,74岁

{@c=map{3+int rand 3}(0)x18;$s=0;$s+=$_ for@c;redo unless$s==72}print"@c"

替代解决方案:

@q=((3,5)x($a=int rand 9),(4,4)x(9-$a));%t=map{(rand,$_)}(0..17);print"@q[@t{sort keys%t}]"

2

TXR(99个字符)

@(bind g@(for((x(gen t(+ 3(rand 3))))y)(t)((pop x))(set y[x 0..18])(if(= [apply + y]72)(return y))))

此表达式生成一个从3到5的无限懒惰随机数列表:

(gen t (+ 3(rand 3)))  ;; t means true: while t is true, generate.

逻辑的其余部分是一个简单的循环,该循环检查此列表的前18个元素是否加起来为72。如果不是,它将弹出一个元素,然后重试。该for循环包含一个称为的隐式块nil,因此(return ...)可用于终止循环并返回值。

请注意,99个字符的长度包括一个终止换行符,这是必需的。


我提交了一个允许(t)替换为()的提交。:)
Kaz 2012年

2

杀伤人员地雷12

4+{⍵,-⍵}?9⍴2

请注意,我已将索引原点设置为0,这意味着数组从0开始。您可以使用进行设置⎕IO←0


问题问一个可以产生所有可能配置的程序。您可以产生模拟的。例如,您无法生产555455555333333343,至少在我看来是如此。
莫里斯·祖卡

2

R,42个字节

a=0;while(sum(a)-72)a=sample(3:5,18,r=T);a

sample,默认情况下,在可能的值(此处3 4 5)之间平均绘制。r=T代表replace=TRUE并允许更换样品。


2

CJam,17个 14字节

CJam比这个挑战要新,但是无论如何这都不是最短的答案,因此这并不重要。

Z5]Amr*I4e]mrp

在这里测试。

要保持总数为72,每个3必须与配对5。所以这是它的工作方式:

Z5]            e# Push [3 5].
   Amr         e# Get a random number between 0 and 9.
      *        e# Repeat the [3 5] array that many times.
       I4e]    e# Pad the array to size 18 with 4s.
           mr  e# Shuffle the array.
             p e# Print it.
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.