N门,K猴子


14

有N个门和K个猴子。最初,所有的门都是关闭的。

第1轮:第1只猴子拜访每扇门并拨动门(如果门关闭,则打开;如果门打开,则关闭)。

第二回合:第一只猴子拜访每扇门并拨动门。然后,第二只猴子每隔第二个门访问一次并切换门。

。。。

。。。

回合k: 第一只猴子拜访每扇门并拨动门。。。。。。。。。。第k只猴子会访问第k个门,然后打开门。

输入: NK(以单个空格分隔)

输出: 打开的门号,每个门号之间用一个空格隔开。

范例

输入:3 3

输出:1 2

限制条件

0 <N <101

0 <= K <= N

注意事项

  • 假设N个门的编号从1到N,K个猴子的编号从1到K

  • 代码最短的一方获胜。另外,显示输出为N = 23,K = 21


受到这个难题的启发吗?
数学冷却器

我只是有一个问题,如果N = K,每个素数门都打开,对不对?
Fabinout

@Fabinout no n=k=3不会输出您1 2错了... 5输出1 2 4有一个模式,但它的明显性不那么明显。
数学冷却器

@Fabinout遵循斐波那契数集的一种非常奇怪的类型,它是非常高级的抽象数学。
数学冷却器

@tryingToGetProgrammingStraight你是对的,我的回忆告诉我答案是质数列表,而平方数列表。
Fabinout

Answers:


14

APL,32 28 26

{(2|+/(⍳⍺)∘.{+/0=⍺|⍨⍳⍵}⍳⍵)/⍳⍺}/⎕

⎕:
      23 21
 1 2 4 8 9 16 18 23 

讲解

  • {+/0=⍺|⍨⍳⍵}是一个函数,返回门(左参数)在回合(右参数)上切换的次数,该次数等于≤ 的因子数

    • ⍳⍵ 从1到1生成数值数组

    • ⍺|⍨计算该数组中每一项的模数

    • 0= 更改为1,那里有一个0,其他所有东西都为0

    • +/ 求和结果数组

  • 外部功能:

    • (⍳⍺)⍳⍵生成从1到N和1到K的数组

    • ∘.{...}对于两个数组的每对元素,应用函数。这给出了切换次数的矩阵,每一行代表一扇门,每一列代表一轮。

    • +/对列求和。这给出了每个门在所有回合中切换次数的数组。

    • 2|模数为2,因此如果门打开,则为1;如果关闭,则为0。

    • (...)/⍳⍺ 最后,生成一个从1到N的数组,并仅选择上一步中数组中存在1的数组。

  • /⎕ 最后,在输入的数字之间插入函数。


编辑

{(2|+⌿0=(,↑⍳¨⍳⍵)∘.|⍳⍺)/⍳⍺}/⎕
  • ,↑⍳¨⍳⍵生成所有“猴子”(如果K = 4,则为1 0 0 0 1 2 0 0 1 2 3 0 1 2 3 4

    • ⍳⍵从1到(K)的数组

    • ⍳¨ 对于其中的每个,生成从1到该数字的数组

    • ,↑将嵌套数组转换为矩阵(),然后分解为简单数组(,

  • (,↑⍳¨⍳⍵)∘.|⍳⍺对于从1到(N)的每个数字,请对每只猴子进行修改。

  • 0=更改为1,那里有一个0,其他所有东西都为0。这给出了切换矩阵:行是每轮猴子,列是门;1表示切换,0表示不切换。

  • +⌿ 对行求和以得到每个门切换次数的数组

其他部分不变


编辑

{(≠⌿0=(,↑⍳¨⍳⍵)∘.|⍳⍺)/⍳⍺}/⎕

使用XOR reduce(≠⌿)代替sum和mod 2(2|+⌿


APL是为高尔夫脚本设计的吗?;-)
celtschk 2014年

@celtschk是的,在某种程度上,是的。它旨在简洁地表达算法。
luser droog

为什么要使用dfn简化{}/而不是仅将N和K作为dfn的参数?
亚当

@Adám因为1)这已经过去了;2)该问题早于“程序或功能”和I / O标准化;3)
行动党

不够公平,但至少可以节省一个字节用i←⍳⍺
亚当

4

GolfScript,33个字符

~:k;),1>{0\{1$)%!k@-&^}+k,/}," "*

如果门从零开始编号,将节省3个字符。

示例(在线):

> 3 3
1 2

> 23 21
1 2 4 8 9 16 18 23

3

Mathematica,104个字符

{n,k}=FromDigits/@StringSplit@InputString[];Select[Range@n,OddQ@DivisorSum[#,If[#>k,0,k+1-#]&]&]~Row~" "

例:

在[1]中:= {n,k} = FromDigits / @ StringSplit @ InputString [];选择[Range @ n,OddQ @ DivisorSum [#,If [#> k,0,k + 1-#]&]& ]〜行〜“”

?23 21

Out [1] = 1 2 4 8 9 16 18 23


1
您可以通过假设输入流来将输入解析为15个字符,例如:{n,k}=%~Read~{Number,Number}
马克·托马斯

3

Ruby,88岁

基于@manatwork的答案。

gets;~/ /
$><<(1..$`.to_i).select{|d|(1..k=$'.to_i).count{|m|d%m<1&&(k-m+1)%2>0}%2>0}*$&

那些狡猾的全局变量总是会破坏语法高亮显示!


抱歉,但是90个字符(修订版2)和86个字符(修订版3)似乎有问题:结果中出现了一个新的数字22。
manatwork

@manatwork好电话,我想我已经以两个字符为代价修复了它。我觉得count可以进一步改善这一点,我希望ruby有一个内置的#sum方法可以解决诸如此类的问题:>
Paul Prestidge

哇!真的很感动。
manatwork

3

Python 3, 97 84

如果猴子出现在偶数个回合中,那根本没有任何改变。如果猴子出现偶数次,则与一轮完全一样。

因此,可以省去一些猴子,而其他猴子只需要开关一次门。

N,K=map(int,input().split())
r=set()
while K>0:r^=set(range(K,N+1,K));K-=2
print(*r)

输出为23 21

1 2 4 8 9 16 18 23

巧妙使用设定操作!我认为您可以缩短range(2-K%2,K+1,2)range(K,0,-2)
xnor 2014年

或者更好的方法是,将for循环替换为while循环:while K>0:r^=set(range(K,N+1,K));K-=2
xnor 2014年

@xnor:谢谢,太好了!
恢复莫妮卡

2

R-74

x=scan(n=2);cat(which(colSums((!sapply(1:x[1],`%%`,1:x[2]))*x[2]:1)%%2>0))

模拟:

> x=scan(n=2);cat(which(colSums((!sapply(1:x[1],`%%`,1:x[2]))*x[2]:1)%%2>0))
1: 23 21
Read 2 items
1 2 4 8 9 16 18 23

2

JavaScript的148 127

function e(n,k){b=array(n);d=[];function a(c){for(i=0;i<n;i+=c)b[i]=!b[i];c<k&&a(c+1)}a(1);for(i in b)b[i]&&d.push(i);return d}

这是(微小的)可读版本:

function e(n, k) {     //define N and K
     b = array(n); //declare all doors as closed
     d = [];     //create array later used to print results

     function a(c) {   //(recursive) function that does all the work
         for (i = 0; i < n; i += c)  //increment by c until you reach N and...
              b[i] = !b[i];  //toggle said doors
         c < k && a(c + 1)  //until you reach k, repeat with a new C (next monkey)
     }
     a(1); //start up A

     for (i in b) b[i] && d.push(i); //convert doors to a list of numbers
     return d //NO, i refuse to explain this....
}   //closes function to avoid annoying errors

演示小提琴

我应该注意,它从0开始计数(从技术上讲是一一错误)


如果将第二行更改为,则可以删除第三行。b=Array(n);这会将您的数组初始化为n长度,其中未定义。!undefined为true,因此第一个猴子通过将全部变为true。
2013年

@ path411非常感谢你!我很惊讶我忘记了“正确的”数组声明是如何工作的!您可以随意使用+1
数学冷却器

有趣。看来,您的问题是我迄今为止看到的唯一一个与我的问题类似的答案,答案是我的N = 23,K = 21。唯一的区别是关断接一个问题,其中包括0和不包括23
Iszi

弄清楚我的出了什么问题,而这个也有同样的问题。对于每一轮,您只需要在所有门上派出一只猴子即可。但是,根据挑战规范,每轮需要有$ i只猴子-其中$ i是您所在轮次的数量。
Iszi 2013年

2

JavaScript 153

(function(g){o=[],f=g[0];for(;i<g[1];i++)for(n=0;n<=i;n++)for(_=n;_<f;_+=n+1)o[_]=!o[_];for(;f--;)o[f]&&(l=f+1+s+l);alert(l)})(prompt().split(i=l=s=' '))

N = 23,K = 21的输出:

1 2 4 8 9 16 18 23  

已在Chrome中进行了测试,但未使用任何新颖的ECMAScript功能,因此可以在任何浏览器中使用!

我知道我永远也不会与其他条目抗衡,并且@tryingToGetProgrammingStrainght已经提交了JavaScript条目,但是N = 23,K = 21的结果与其他所有人都没有得到相同的结果,所以我想我可以试试我自己的版本。

编辑:带注释的源(在再次查看时,我发现了保存另外3个字符的地方,因此它可能仍会得到改善...)

(function(g) {
    // initialise variables, set f to N
    o = [], f = g[0];

    // round counter
    // since ++' ' == 1 we can use the same variable set in args
    for (; i < g[1]; i++)
        // monkey counter, needs to be reset each round
        for (n = 0 ; n <= i; n++)
            // iterate to N and flip each Kth door
            for (_ = n; _ < f; _ += n + 1)
                // flip the bits (as undef is falsy, we don't need to initialise)
                // o[_] = !~~o[_]|0; // flips undef to 1
                o[_] = !o[_]; // but booleans are fine
    // decrement f to 0, so we don't need an additional counter
    for (;f--;)
        // build string in reverse order
        o[f] && (l = f + 1 + s + l); // l = (f + 1) + ' ' + l
    alert(l)
    // return l // use with test
// get input from user and store ' ' in variable for use later
})(prompt().split(i = l = s = ' '))
// })('23 21'.split(i = l = s = ' ')) // lazy...

// == '1 2 4 8 9 16 18 23  '; // test

做得好!如果您还提供可读和注释的版本,我可能会+1
Math chiller

答案已更新!由于我无法评论您的答案,因此要添加到@ path411的评论中,您可以设置b = [],并且空索引仍然未定义,这样可以为您节省另外6个字符!
Dom Hastings

我这样做已经....
数学机组

1

Ruby-65个字符

(1..n).each{|d|
t=0
(1..k).each{|m|t+=n-m+1 if d%m==0}
p d if t%2>0}

n = 23, k = 21 # => 1 2 4 8 9 16 18 23 

这是计算,用伪代码:

  • 令s(d)为k圈后门d被触摸的次数。
  • s(d)= sum(m = 1..m = k)(d%m == 0?(n-m + 1):0)
  • 如果s(d)%2 = 1(或> 0),则k圈后门d打开

如果您不确定s(d)的表达式是正确的,请这样看:

  • 令s(d,r)为r回合后门d被触摸的次数。
  • s(d,k)-s(d,k-1)= sum(m = 1,..,m = k)(d%m == 0?1:0)
  • s(d,k-1)-s(d,k-2)= sum(m = 1,..,m =(k-1))(d%m == 0?1:0)
  • ...
  • s(d,2)-s(d,1)= d%2 == 0?1:0
  • s(d,1)= 1
  • 将双方求和以获得s(d)的上述表达式,该表达式等于s(d,k)

非常简洁!不过n,它k来自何处?并且输出似乎由换行符而不是空格分隔。
保罗·普雷斯蒂奇

1

PowerShell的:132

高尔夫球代码:

$n,$k=(read-host)-split' ';0|sv($d=1..$n);1..$k|%{1..$_|%{$m=$_;$d|?{!($_%$m)}|%{sv $_ (!(gv $_ -Va))}}};($d|?{(gv $_ -Va)})-join' '

取消注释的代码:

# Get number of doors and monkeys from user as space-delimited string.
# Store number of doors as $n, number of monkeys as $k.
$n,$k=(read-host)-split' ';

# Store a list of doors in $d.
# Create each door as a variable set to zero.
0|sv($d=1..$n);

# Begin a loop for each round.
1..$k|%{

    # Begin a loop for each monkey in the current round.
    1..$_|%{

        # Store the current monkey's ID in $m.
        $m=$_;

        # Select only the doors which are evenly divisible by $m.
        # Pass the doors to a loop.
        $d|?{!($_%$m)}|%{

            # Toggle the selected doors.
            sv $_ (!(gv $_ -Va))
        }
    }
};

# Select the currently open doors.
# Output them as a space-delimited string.
($d|?{(gv $_ -Va)})-join' '

# Variables cleanup - don't include in golfed code.
$d|%{rv $_};rv n;rv d;rv k;rv m;

# NOTE TO SELF - Output for N=23 K=21 should be:
# 1 2 4 8 9 16 18 23

哦,我知道我的问题是什么。我误解了这个问题-这不是 100个储物柜的问题。就是这样,占用了一个缺口!这将需要更多的工作...
Iszi

1
甜!正确地解决它来满足挑战要求,最终只能获得6个字符。
Iszi 2013年

0

Powershell,66个字节

基于Cary Swoveland的答案

param($n,$k)1..$n|?{$d=$_
(1..$k|?{($n-$_+1)*!($d%$_)%2}).Count%2}

测试脚本:

$f = {

param($n,$k)1..$n|?{$d=$_
(1..$k|?{($n-$_+1)*!($d%$_)%2}).Count%2}

}

@(
    ,(3, 3   , 1,2)
    ,(23, 21 , 1, 2, 4, 8, 9, 16, 18, 23)
) | % {
    $n,$k,$expected = $_
    $result = &$f $n $k
    "$("$result"-eq"$expected"): $result"
}

输出:

True: 1 2
True: 1 2 4 8 9 16 18 23
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.