任意随机


26

随机性很有趣。没有意义的挑战很有趣。

编写一个函数,在给定整数输入的情况下n,将输出介于和(包括)之间的一(无序,唯一的)精确n随机整数,以使所有整数的总和等于。1n^2n^2

随机性也不会是均匀的,只要每个有效集有发生非零机会。

以字节为单位的最短答案(每种语言)获胜。

例子

Input (n) = 1, Target (n^2) = 1
Sample of possible outputs:
1

Input = 2, Target = 4
Sample of possible outputs:
3, 1
1, 3

Input = 3, Target = 9
Sample of possible outputs:
6, 1, 2
3, 5, 1
4, 3, 2

Input = 4, Target = 16
Sample of possible outputs:
1, 3, 5, 7
2, 4, 1, 9
8, 3, 1, 4

Input = 5, Target = 25
Sample of possible outputs:
11, 4, 7, 1, 2
2, 3, 1, 11, 8
6, 1, 3, 7, 8

Input = 8, Target = 64
Sample of possible outputs:
10, 3, 9, 7, 6, 19, 8, 2
7, 16, 2, 3, 9, 4, 13, 10
7, 9, 21, 2, 5, 13, 6, 1

奖励任务:是否有一个公式可以计算给定的有效排列数量n


2
相关,但完全不同
Giuseppe

1
(p / s:如果您使用的是快速算法,但占用更多字节,请考虑等到速度版(当前在沙箱中)发布。)
user202729

1
@EriktheOutgolfer尽管有(比)生成所有集合并选择随机集合更好的方法,但是它们很难实现,而且可能更长。保留它们作为速度版。
user202729

2
套数为OEIS A107379
nwellnhof

1
都是。请参阅注释“还将n ^ 2划分为n个不同部分的数量”。
nwellnhof '18

Answers:


9

Brachylog(v2),15个字节(随机)或13个字节(所有可能性)

随机

~lℕ₁ᵐA+√?∧A≜₁ᵐ≠

在线尝试!

函数提交(在TIO中使用包装程序进行查看,使其成为完整的程序)。

说明

~lℕ₁ᵐA+√?∧A≜₁ᵐ≠
~l               Specify a property of a list: its length is equal to the input,
    ᵐ              and it is composed entirely of
  ℕ₁                 integers ≥ 1,
       √           for which the square root of the
      +              sum of the list
        ?              is the input.
     A   ∧A      Restricting yourself to lists with that property,
           ≜₁      pick random possible values
             ᵐ       for each element in turn,
              ≠    until you find one whose elements are all distinct.

所有可能性

~lℕ₁ᵐ<₁.+√?∧≜

在线尝试!

函数提交,生成所有可能的输出。

说明

~lℕ₁ᵐ<₁.+√?∧≜
~l               Specify a property of a list: its length is equal to the input,
    ᵐ              it is composed entirely of
  ℕ₁                 integers ≥ 1,
     <₁            it is strictly increasing,
         √         and the square root of the
        +            sum of the list
          ?            is the input.
       .   ∧≜    Generate all specific lists with that property.

我对此感到很惊讶∧≜(您通常必须编写∧~≜才能对输出而不是输入进行暴力破解),但是事实证明它具有输入=输出假设,因此无论您采用哪种方式运行。

奖励任务

为了深入了解可能性的顺序,我创建了一个不同的TIO包装器,该包装器在连续的整数上运行程序以给出输出计数的顺序:

1,1,3,9,30,110,436,1801,7657,33401

前往OEIS时发现,这已经是一个已知序列A107379,几乎与问题中描述的一样(显然,如果将其限制为奇数,则将获得相同的序列)。该页面列出了该序列的几个公式(尽管没有一个特别简单;第二个看起来像是该值的直接公式,但我不理解该表示法)。


第二个公式是“的x^(n*(n-1)/2)级数展开式的系数Product_{k=1..n} 1/(1 - x^k)”(不幸的是,根本不是直接的)
user202729

在随机标记步骤(例如A≠≜₁ᵐ)之前放置“所有不同”约束将平均缩短运行时间。
致命的

我不明白您为何将其设为社区Wiki。这些是过时的方式,可以编辑帖子,然后再进行编辑。
管道


7

05AB1E,11 个字节

nÅœʒDÙQ}sùΩ

在线尝试验证所有测试用例

说明:

n             # Take the square of the (implicit) input
              #  i.e. 3 → 9
 Ŝ           # Get all integer-lists using integers in the range [1, val) that sum to val
              #  i.e. 9 → [[1,1,1,1,1,1,1,1,1],...,[1,3,5],...,[9]]
   ʒ   }      # Filter the list to only keep lists with unique values:
    D         # Duplicate the current value
     Ù        # Uniquify it
              #  i.e. [2,2,5] → [2,5]
      Q       # Check if it's still the same
              #  i.e. [2,2,5] and [2,5] → 0 (falsey)
        s     # Swap to take the (implicit) input again
         ù    # Only leave lists of that size
              #  i.e. [[1,2,6],[1,3,5],[1,8],[2,3,4],[2,7],[3,6],[4,5],[9]] and 3
              #   → [[1,2,6],[1,3,5],[2,3,4]]
          Ω   # Pick a random list from the list of lists (and output implicitly)


5

R68、75、48个字节(随机)和70个字节(确定性)

@Giuseppe的拒绝采样方法:

function(n){while(sum(F)!=n^2)F=sample(n^2,n);F}

在线尝试!

高尔夫原件:

function(n,m=combn(1:n^2,n))m[,sample(which(colSums(m)==n^2)*!!1:2,1)]

在线尝试!

*!!1:2业务是为了避免奇怪的方式sample行动时,第一个自变量的长度为1。


@Giuseppe“已修复” :-)
ngm

非常好。使用p直接作为指标,而不是计算它和再使用它应该节省一些字节。
朱塞佩

1
我也有function(n){while(sum(F)!=n^2)F=sample(n^2,n);F}48位...
朱塞佩

1
@ J.Doe调用像时,为了避免这个问题sample(2,1)与情况n=2。因此,rep只需保证这永远不会发生。也许有更好的办法,但这很快,我很生气sample
ngm

1
如果您的元问题得到否x*!!1:2rep(x,2)则可以用over 保存一个字节。
J.Doe

4

果冻,9个字节

²œcS=¥Ƈ²X

在线尝试!

生成列表[1..n²]的所有n个组合,进行过滤以保留总和为n²的组合,然后随机选择一个。


4

爪哇10,250个 242 222字节

import java.util.*;n->{for(;;){int i=n+1,r[]=new int[i],d[]=new int[n];for(r[n<2?0:1]=n*n;i-->2;r[i]=(int)(Math.random()*n*n));var S=new HashSet();for(Arrays.sort(r),i=n;i-->0;)S.add(d[i]=r[i+1]-r[i]);if(!S.contains(0)&S.size()==n)return S;}}

-20个字节,感谢@nwellnhof

当心,Java来了。。它只是其他四个答案加起来的五倍,所以我想还不错。
不过,它确实在不到2秒的时间内n=1完成了n=25(合并)运行,因此我也可能会将修改后的版本发布到此挑战的快速版本中(目前仍在沙盒中)。

在线尝试。

说明:

用伪代码执行以下操作:

1)生成一个大小为数组的数组,n+1其中包含:0n平方和n-1范围内的随机整数[0, n squared)
2)对该数组进行排序
3)创建第二个大小数组,n其中包含对的正向差异
这前三个步骤将为我们提供一个包含n随机数的数组整数(在[0, n squared)求和的n平方的范围内
。4a)如果并非所有随机值都是唯一的,或者它们中的任何一个为0:请从步骤1开始重试
4b)否则:返回此差值数组作为结果

至于实际的代码:

import java.util.*;      // Required import for HashSet and Arrays
n->{                     // Method with int parameter and Set return-type
  for(;;){               //  Loop indefinitely
    int i=n+1,           //   Set `i` to `n+1`
        r[]=new int[i];  //   Create an array of size `n+1`
    var S=new HashSet(); //   Result-set, starting empty
    for(r[n<2?           //   If `n` is 1:
           0             //    Set the first item in the first array to:
          :              //   Else:
           1]            //    Set the second item in the first array to:
             =n*n;       //   `n` squared
        i-->2;)          //   Loop `i` in the range [`n`, 2]:
      r[i]=              //    Set the `i`'th value in the first array to:
           (int)(Math.random()*n*n); 
                         //     A random value in the range [0, `n` squared)
    for(Arrays.sort(r),  //   Sort the first array
        i=n;i-->0;)      //   Loop `i` in the range (`n`, 0]:
      S.add(             //    Add to the Set:
        r[i+1]-r[i]);    //     The `i+1`'th and `i`'th difference of the first array
    if(!S.contains(0)    //   If the Set does not contain a 0
       &S.size()==n)     //   and its size is equal to `n`:
      return S;}}        //    Return this Set as the result
                         //   (Implicit else: continue the infinite loop)

1
n=25在不到2秒的时间内令人印象深刻!我必须通读解释,然后看它是如何做到的。它仍然是蛮力方法吗?
Skidsdev

它是统一的吗?-
user202729

@ user202729虽然我不确定如何证明,但我认为是。Java内置函数是统一的,它首先使用它来获取范围内的随机值[0, n squared),然后计算排序后的随机值之间的差异(包括前导0和尾随n squared。因此,我敢肯定,这些差异也是统一的。但是再次,我不确定如何证明这一点。随机性的均匀性并不是我的专长
凯文·克鲁伊森

3
您从未读过差异数组,d或者我错过了什么?
nwellnhof


4

Perl 6,41个字节

{first *.sum==$_²,(1..$_²).pick($_)xx*}

在线尝试!

  • (1 .. $_²) 是从1到输入数字平方的数字范围
  • .pick($_) 随机选择该范围的不同子集
  • xx * 无限复制前一个表达式
  • first *.sum == $_² 选择那些数字集的第一个,其总和为输入数字的平方


2

Pyth,13 12字节

Ofq*QQsT.cS*

在这里在线尝试。请注意,对于大于5的输入,在线解释器会遇到MemoryError。

Ofq*QQsT.cS*QQQ   Implicit: Q=eval(input())
                 Trailing QQQ inferred
          S*QQQ   [1-Q*Q]
        .c    Q   All combinations of the above of length Q, without repeats
 f                Keep elements of the above, as T, where the following is truthy:
      sT            Is the sum of T...
  q                 ... equal to...
   *QQ              ... Q*Q?
O                 Choose a random element of those remaining sets, implicit print

编辑:采用其他方法保存了一个字节。先前版本: Of&qQlT{IT./*


2

Python 3中136个134 127 121 114字节

from random import*
def f(n):
	s={randint(1,n*n)for _ in range(n)}
	return len(s)==n and sum(s)==n*n and s or f(n)

在线尝试!

一个评论者纠正了我,这现在在f(5)而不是f(1)处达到了递归最大深度。更接近成为一个真正的竞争性答案。

我已经看过它一次执行f(5),并且我正在尝试使用shuffle来实现它。

我尝试为做一些lambda表达式s=...,但这对字节没有帮助。也许其他人可以这样做: s=(lambda n:{randint(1,n*n)for _ in range(n)})(n)

感谢Kevin削减了另外7个字节。


1
因此,如果生成的集合无效,则使用递归“重新生成”集合吗?如果代码达到递归深度,肯定是您的代码有问题f(1),应该在生成的唯一可能的数组n=1是。[1]这里还有很多多余的空白要删除。请记住,这是一个代码高尔夫球挑战,所以目标是达到最低字节数
Skidsdev

1
range(1,n)-> range(n)我相信应该可以解决该错误。
乔纳森·艾伦

1
应该可以修复您的错误,并删除多余的空格。我想还有很多打高尔夫球的地方
Skidsdev

1
虽然递归略有恶化5到4,你可以结合你的两个return语句是这样的:return len(s)==n and sum(s)==n*n and s or f(n)在线试玩114个字节)。
凯文·克鲁伊森

1
您可以将所有内容全部放在一行上。111字节
Jo King

2

APL(Dyalog Unicode),20 字节SBCS

匿名前缀lambda。

{s=+/c←⍵?s←⍵*2:c⋄∇⍵}

在线尝试!

{…… } “ dfn”;是争论

⍵*2 争论的平方

s← 分配给s平方

⍵?n从1…中 找到随机索引,s而无需替换

c← 分配给c(代表c

+/ 总结一下

s= 相比于 s

: 如果相等

  c 返回候选人

 其他

  ∇⍵ 递归论证


您看到H.PWiz的 18个字节了吗?
ngn

@ngn不,显然不是,但是在发布之前,我检查了是否未发布APL解决方案。你们为什么不‽
Adám18年

好吧,一旦我打完高尔夫球并将其展示给果园,几乎没有动力去发贴了:)
ngn

@ngn对您来说,不,但对我而言。
亚当

1
当然,我认为您在这里普及apl的工作非常出色。我只是确保您知道已经找到了更短的解决方案,所以可能最好解释其中一个(或一个变体),而不是
ngn

2

APL(Dyalog Classic),18字节

(≢?≢×≢)⍣(0=+.-∘≢)⍳

在线尝试!

用途 ⎕io←1

产生数字 1 2 ... n

(... )⍣(... )继续应用左侧的功能,直到右侧的功能返回true

长度,即 n

≢?≢×≢选择n1到2之间的随机不同整数n

+.-∘≢ 从每个数字中减去长度并求和

0= 如果总和为0,请停止循环,否则重试


1

MATL18 13字节

`xGU:GZrtsGU-

在线尝试!

`	# do..while:
x	# delete from stack. This implicitly reads input the first time
	# and removes it. It also deletes the previous invalid answer.
GU:	# paste input and push [1...n^2]
GZr	# select a single combination of n elements from [1..n^2]
tsGU-	# is the sum equal to N^2? if yes, terminate and print results, else goto top

我不会在R中尝试-随机字符几乎永远不会产生有效的程序。
ngm

@ngm哈哈哈,我想有一个适当的解释。
朱塞佩

1

Japt,12个字节

²õ àU ö@²¥Xx

试试吧

                 :Implicit input of integer U
²                :U squared
 õ               :Range [1,U²]
   àU            :Combinations of length U
      ö@         :Return a random element that returns true when passed through the following function as X
        ²        :  U squared
         ¥       :  Equals
          Xx     :  X reduced by addition

根据OP的评论,输出中元素的顺序无关紧要,因此à应该没问题。
卡米尔·德拉卡里

谢谢,@ KamilDrakari。更新。
毛茸茸的

1

Java(JDK),127个字节

n->{for(int s;;){var r=new java.util.TreeSet();for(s=n*n;s>0;)r.add(s-(s-=Math.random()*n*n+1));if(r.size()==n&s==0)return r;}}

在线尝试!

无限循环,直到符合条件的集合匹配为止。

我希望您有时间,因为它非常实用!如果不超时,它甚至不能达到10。


您可以通过更改if(r.size()==n&s==0)为来打高尔夫球3个字节if(r.size()+s==n)
凯文·克鲁伊森

@KevinCruijssen我已经想过这个问题了,但是我真的无法由于S1可能是-1和n可能是大小() - 1
奥利维尔·格雷瓜尔

等等,您一直在向集合中添加项目s>0,因此大小可以大于n。好的,在那种情况下,它确实是行不通的。n是一个常数,但不幸的是两个sr.size()是变量既可以是低于或高于0n分别。
凯文·克鲁伊森

1

批处理,182145字节

@set/an=%1,r=n*n,l=r+1
@for /l %%i in (%1,-1,1)do @set/at=n*(n-=1)/2,m=(r+t+n)/-~n,r-=l=m+%random%%%((l-=x=r+1-t)*(l^>^>31)+x-m)&call echo %%l%%

说明:给定降序选择数字,计算最小和最大允许拾取,并选择范围内的随机值。输入示例4

  • 我们从左16开始。我们不能选择11个或更多,因为剩余的3个选择必须加到至少6个。我们还需要选择至少6个,因为如果我们仅选择5个,则剩余的3个选择只能添加到9个,这不是足够用于16。我们从6到10中选择一个随机值,例如6。
  • 我们还有10个。我们不能选择8个或更多,因为其余2个必须至少增加3个。碰巧的是,我们不能选择6个或更多,因为我们上次选择6个。我们还需要至少选择5个,因为如果我们仅选择4个,则其余2个选择只能加到5,总共15个。我们选择5到5之间的随机值,例如5(!)。
  • 我们还有5个。我们不能选择5个或更多,因为剩余的选择必须加到至少1,并且因为我们上次选择5个。我们还需要至少选择3个,因为如果我们仅选择2个,则剩余的选择只能是1个,总计14个。我们选择3到4个随机值,例如4。
  • 我们还有1个。事实证明,该算法选择1到1的范围,我们选择1作为最终数字。

1

JavaScript中,647个 291 261 260 259 251 239字节

感谢@Veskah原始版本中的-10个字节,“哦,是的,您输出了所有的集合,而挑战要求返回一个随机的集合”

(n,g=m=n**2,r=[...Array(g||1)].map(_=>m--).sort(_=>.5-Math.random()).slice(-n),c=_=>eval(r.join`+`),i=_=>r.includes(_))=>[...{*0(){while(g>1&&c()!=g){for(z of r){y=c();r[m++%n]=y>g&&!(!(z-1)||i(z-1))?z-1:y<g&&!i(z+1)?z+1:z}}yield*r}}[0]()]

在线尝试!

创建一个n^2基于1的索引的数组,对数组进行随机排序,n从数组中切片元素。随机元素的总和不等于n^2随机元素的循环数组;如果数组元素的总和大于n^2且当前元素-1不等于零或当前元素-1不在当前数组中,则减去1; 如果array的总和小于n^2且当前元素+1不在array中,则添加1到element。如果数组和等于n^2中断循环,则输出数组。


1
通过将z.join拉入一个变量来获得637个字节,以及k++
Veskah

@Veskah这两个while循环可能也可以简化为接受参数的单个函数的主体。并可以用条件运算符(三元)代替if..else语句;代码的其他部分,很可能会针对高尔夫进行调整;即删除let语句。
guest271314

@Veskah 601字节,未用三进制替换为if..else
guest271314 '18

1
噢,是的,您要输出所有集合,而挑战要求您随机返回一个集合(有关更多详细信息,请参阅OP注释)
Veskah

@Veskah必须误解了挑战和示例,或者过于专注于解决问题的这一部分额外任务:是否有公式来计算给定的有效排列数量n?” 。测试算法是否一致返回n^2在单个调用函数中生成的输出数组的预期结果,并同时考虑与此问题相似的N维N ^ N数组(由N填充)
guest271314

0

Japt,20字节

²õ ö¬oU íUõ+)Õæ@²¥Xx

在线尝试!

极其大量地利用“非均匀”随机性,几乎总是输出第一个n奇数,恰好相加为n^2。从理论上讲,它可以输出任何其他有效集,尽管我只能为small确认这一点n

说明:

²õ                      :Generate the range [1...n^2]
   ö¬                   :Order it randomly
     oU                 :Get the last n items
        í   )Õ          :Put it in an array with...
         Uõ+            : The first n odd numbers
              æ_        :Get the first one where...
                  Xx    : The sum
                ²¥      : equals n^2


0

C(GCC) 128个 125字节

p(_){printf("%d ",_);}f(n,x,y,i){x=n*n;y=1;for(i=0;++i<n;p(y),x-=y++)while(rand()&&(n-i)*(n-i+1)/2+(n-i)*(y+1)+y<x)y++;p(x);}

在线尝试!

-3个字节,感谢ceilingcat

注意:该概率离统一非常非常远。请参阅解释以了解我的意思,以及一种更好的方法来测试其工作原理(通过使分布更接近于均匀[但仍与之相去甚远])。

怎么样?

基本思想是只选择递增的数字,而不用担心重复。每当我们选择一个数字时,如果允许的话,我们都有非零的机会“跳过”它。

xky

y+(y+1)+(y+2)+...
x
k(k+1)2+k(y+1)+y<x

尽管如此,逻辑上还是有机会丢弃任何y满足上述方程式的东西。

代码

p(_){printf("%d ",_);}  // Define print(int)
f(n,x,y,i){             // Define f(n,...) as the function we want
    x=n*n;              // Set x to n^2
    y=1;                // Set y to 1
    for(i=0;++i<n;){    // n-1 times do...
        while(rand()&&  // While rand() is non-zero [very very likely] AND
            (n-i)*      // (n-i) is the 'k' in the formula
            (n-i+1)/2+  // This first half takes care of the increment
            (n-i)*(y+1) // This second half takes care of the y+1 starting point
            +y<x)       // The +y takes care of the current value of y
        y++;            // If rand() returned non-zero and we can skip y, do so
    p(y);               // Print y
    x-=y++;             // Subtract y from the total and increment it
    }p(x);}             // Print what's left over.

我提到的用于更好地测试代码的技巧包括用替换rand()&&rand()%2&&以便跳过给定y的可能性为50-50,而不是使用RAND_MAX任何给定y的机会为1 。


如果有人检查我的数学的一致性,我会喜欢的。我还想知道这种解决方案是否可以使统一的随机速度挑战变得简单。该公式在答案上设置了上限和下限,在该范围内的统一随机数是否会导致统一的随机结果?我不明白为什么不这样做-但我有一段时间没有做很多组合了。
LambdaBeta

建议p(y),x-=y++)while(rand()&&(i-n)*((~n+i)/2+~y)+y<x)y++;而不是){while(rand()&&(n-i)*(n-i+1)/2+(n-i)*(y+1)+y<x)y++;p(y);x-=y++;}
ceilingcat '18

@ceilingcat我喜欢您发现的这些小改进。我一直都专注于整体算法,忘了为实现进行优化(一旦我有了一个非高尔夫来源,我就基本上进入了自动驾驶高尔夫模式-所以我省了很多

嘿,拥有语法语法的不仅仅是您。我在许多类似的C / C ++答案中发现没有什么改进(除非在您的答案之外,@ ceilingcat通常会将它们抢购一空)。
扎卡里

是的,我注意到你们两个可能是最活跃的C / C ++推杆(我们可以使用推杆将高尔夫类比延伸到最后几个击球吗?为什么不!)。这总是让我印象深刻,您甚至可以充分理解高尔夫球代码以改进它。
LambdaBeta

0

干净,172字节

import StdEnv,Math.Random,Data.List
? ::!Int->Int
?_=code{
ccall time "I:I"
}
$n=find(\s=length s==n&&sum s==n^2)(subsequences(nub(map(inc o\e=e rem n^2)(genRandInt(?0)))))

在线尝试!


0

Python(2或3),84个字节

from random import*;l=lambda n,s=[]:(sum(s)==n*n)*s or l(n,sample(range(1,n*n+1),n))

在线尝试!

达到最大递归深度约l(5)



0

Mathematica 40字节

RandomChoice[IntegerPartitions[n^2, {n}]]

1
首先,它是n ^ 2,而不是2 ^ n。其次,您的程序必须是一个功能,也是一个高尔夫功能。试试这个 RandomChoice@IntegerPartitions[#^2,{#}]&
J42161217 '18

1
而且结果必须是(无序的,唯一的),但是此函数在两个函数中均失败
J42161217 '18

0

Wolfram语言(Mathematica),49个字节

(While[Tr[s=RandomSample[Range[#^2],#]]!=#^2];s)&

在线尝试!

@ J42161217的高尔夫版本。


Wolfram语言(Mathematica),62字节

Range[#-1,0,-1]+RandomChoice@IntegerPartitions[#*(#+1)/2,{#}]&

在线尝试!

怎么运行的

n2nn2(n2n)/2=(n2+n)/20n1n10


奖励任务的答案

奖励任务:是否有一个公式可以计算给定的有效排列数量n

part(n,k)nk

part(n,k)=part(n1,k1)+part(nk,k)

part(n,1)=1n<kpart(n,k)=0

part(n2+n2,n)

在Mathematica中:

Length@IntegerPartitions[#*(#+1)/2,{#}]&

在线尝试!


这是代码高尔夫球。49字节(While[Tr[s=RandomSample[Range[#^2],#]]!=#^2];s)&
J42161217 '18
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.