圣诞老人送礼物要花多长时间?


12

不久前,我发布了这个挑战,它涉及圣诞老人需要送多少礼物的精灵。

由于人口增加,圣诞老人在今年的时间上压力更大。尽管过去我们非常异步地运行,但是我们开始尝试越来越同步。因此,圣诞老人需要知道他要花多长时间才能将给定数量的精灵送给每个地区的礼物。

煤炭的重量在过去两年中没有变化-它仍然比礼物重,因此圣诞老人在屋子里每个顽皮的人需要三个精灵,在屋子里每个好人需要两个精灵。

精灵们整年都在圣诞节训练,因此分娩之间不需要任何休息。他们一次只能将礼物送到一所房子,并且必须回去圣诞老人的雪橇并收集下一份礼物,然后再去下一所房子。由于我没有自由分享的理由,精灵们不会花时间在圣诞老人的雪橇和房屋之间旅行(但只能在圣诞老人的雪橇在屋顶上时旅行),他的雪橇也不花时间在房屋之间移动。(圣诞老人的雪橇确实需要在每个房子之间移动以收集燃料,但我已经说了太多了。)

运送礼物的精灵需要花费4秒*每个运送礼物,运送煤炭的精灵需要花费5秒*每个运送礼物(根据圣诞老人航空管理局的规定,戴有煤尘的手套必须在焚化后立即焚化。登上雪橇,这需要一些时间)。此外,必须按照从左到右在地图上的顺序来访问房屋,并且在所有礼物都已交付到他们当前所在的房屋之前,精灵无法开始将礼物交付到其他房屋。

如果我们假设圣诞老人在该地区拥有足够多的精灵,那么只需要花费很长时间就可以向顽皮名单上的某人送礼物,每只房子5秒,如果每个人都很好,则每只房子4秒。

但是,与前几个季节相比,这个即将到来的圣诞节圣诞老人的每个区域可能没有足够的精灵,因此4秒是将礼物运送到任何给定房屋所需的最短时间*,除非有0好人和​​0个顽皮的人,在这种情况下,将需要0秒。

另外,即使其中一所房子的顽皮名单上也有人,圣诞老人也将需要至少三个精灵。如果至少其中一所房子的某个人在好名单上,而没有一个人在顽皮的名单上,那么圣诞老人将需要至少两个精灵。如果没有一所房子符合圣诞节的气氛,那么任何数量的精灵(包括0个)将花费0秒。

在圣诞老人的地图上,一栋房子用表示*,每栋房子用分割+。圣诞老人仍然使用与其他挑战相同的地图,但是我将在此处包括有关它们的文档。

房子的两边都会有一个数字-左边的数字代表房子里顽皮的人数,右边的数字代表房子里好人的人数。如果一侧没有数字,则将其解释为0。

我知道这听起来很疯狂,但是有些人“不喜欢圣诞节”,所以有时候,房子的两边可能没有数字。

圣诞老人的一张地图可能看起来像这样。

1*3+2*+*5+*+4*7

假设圣诞老人的雪橇上有九只精灵。

  1. (0s)第一所房子有1个顽皮的人和3个好人。其中三只精灵需要五秒钟来运送煤炭,六只礼物需要四秒钟来运送礼物。五秒钟后,圣诞老人的雪橇移到下一所房子

  2. (5s)第二宫有2个顽皮和0个好人。六个精灵运送煤炭,耗时五秒钟。五秒钟后,圣诞老人的雪橇移到下一所房子

  3. (10s)第三宫有0个顽皮和5个好人。其中有八只精灵送来了四个礼物(被遗忘的那一个无法送出礼物)。四秒钟后,所有的小精灵都回来了,其中两个去运送另一个礼物(雪橇必须等到小精灵回来之后才能去下一所房子),再花四秒钟

  4. (18s)第四宫不属于圣诞节气氛,所以有0个顽皮和0个好人,因此被跳过

  5. (18岁)第五宫有4个顽皮的人和7个好人。这有点复杂...

    I.所有九个精灵都去交付三份煤礼物(离开t + 0,返回t + 5s)II。5s之后,他们又回到了雪橇上,其中三个去送了最后一个煤炭礼物(离开t + 5s,返回t + 10s),而其他六个去了三个礼物(离开t + 5s,返回t + 9s)。

    三,四秒钟后,六个小精灵又回来了,又去送了三个精美的礼物(离开t + 9s,返回t + 13s)。

    IV。他们离开后一秒钟,三个送煤的精灵回来了,其中两个离开了,送了最后一个漂亮的礼物(离开+ 10s,返回t + 14s)

  6. (18 + 14 = 32秒)圣诞老人完成了向该地区运送礼物的工作。

如我们所见,圣诞老人总共需要32秒钟才能将礼物运送到该地区。不过,那是圣诞老人的一张地图的过于简化的版本。通常,圣诞老人的地图有多条线,并且呈正方形,以便更好地适合他的列表。法线贴图可能看起来像这样(\n每行的结尾处是a )

1*2+*+*4+1*
2*4+3*+1*6+*
*+*+4*2+1*1
*4+*3+1*+2*3
3*10+2*+*5+*

如果有26个精灵(或更多精灵),它将花费圣诞老人71秒
如果有20个精灵,圣诞老人将需要76秒
如果有15个精灵,圣诞老人将需要80秒
3个精灵,圣诞老人需要288秒
如果有2个精灵(或更少的精灵),那是不可能的。

哦,还有一件事- 精灵送出礼物的顺序很重要(由于送给调皮的人/好人的时间差),所以您的代码应始终输出最少的时间,精灵可以送出礼物。

挑战

帮助圣诞老人确定一定数量的精灵送礼物需要多长时间。

房屋

  • 房子用 *
  • 房屋被分割 +
  • 房子左侧的数字表示顽皮的人数(没有数字表示0)
  • 右边的数字表示好人的数量(没有数字表示0)
  • \n输入中可能包含换行符(),也应将其拆分

精灵

  • 圣诞老人需要三名精灵的调皮人的帮助(煤炭比礼物重得多),这些精灵需要五秒钟*才能送出礼物
  • 圣诞老人需要两位精灵的帮助,才能帮助好人,而这两位精灵需要四秒钟*才能送出礼物
  • 如果房子的两边都没有数字,圣诞老人将不会去参观那所房子,因此将不需要任何时间(不具备圣诞节精神的人甚至不配煤)

圣诞老人

  • 圣诞老人必须将礼物一一送到房子
  • 直到所有精灵都回到雪橇上并且所有礼物都被送到那所房子之前,圣诞老人才能进入下一所房子(我们不想把精灵留在后面,对吧?)
  • 圣诞老人的雪橇不花时间在一家到另一家旅行(再次,出于我无法自由分享的原因)

该怎么办

给定一张房屋和许多精灵的地图,打印圣诞老人将礼物运送到地图上的房屋要花费多长时间。

*(我可能不会分享精灵送出礼物所花费的时间。我无法确认也不能否认此挑战所包含的时间是正确的)

规则

  • 有两个输入-地图和精灵数量。输入可以用作函数的参数,也可以来自STDIN或等效输入。如果用您的语言不可能接受两个输入,那么只有到那时,您才可以将两个输入作为单个输入字符串接受,并由通常不在输入中的某个字符定界(不是+*\n0-9-输入字符串不能含糊)例如 ,
  • 精灵数将始终为非负整数(0有效)
  • 输出可以是函数的返回值,也可以输出STDOUT或等效输出。如果圣诞老人无法将给定数量的精灵送给指定区域的礼物,则必须输出一致的负数或一致的消息,其中没有任何数字
  • 打印到STDERR的所有内容都将被忽略,因此您可能不会将结果或错误消息打印到STDERR
  • 给定一个区域的精灵数量无效,您的程序不会崩溃
  • 输出应该仅是圣诞老人以给定数量的精灵运送礼物所花费的总时间。
  • 输出应始终是精灵送出礼物所需的最少时间
  • 输入只包含数字,+*和换行\n(除非你指定其他字符其中输入包括,如果你的语言不能把两个输入(看第一条规则)
  • 适用标准漏洞

测试用例

"1*1", 5 elves => 5
"1*1", 3 elves => 9
"1*2", 7 elves => 5
"1*2", 5 elves => 10
"1*2", 3 elves => 13
"2*1", 8 elves => 5
"2*1", 5 elves => 9
"2*1", 3 elves => 14
"1*" , 3 elves => 5
"1*" , 2 elves => (error message)
"*1" , 2 elves => 4
"*1" , 0 elves => (error message)
"*"  , 0 elves => 0

"1*1+1*1",   5 elves => 10
"1*1+1*1",   3 elves => 18
"1*1+*+1*1", 3 elves => 18
"1*2+2*1",   8 elves => 10
"1*2+2*1",   7 elves => 14
"1*2+2*1",   6 elves => 18
"1*2+2*1",   3 elves => 27
"1*2+2*1",   2 elves => (error message)
"*+*+*+*",   2 elves => 0
"*+*+*+*",   0 elves => 0

"1*3+2*+*5+*+4*7", 9 elves => 32

(希望我一切都正确)

计分

圣诞老人每天都在花时间看很多事情-他要送的所有礼物,他所有的精灵,他要送礼物的所有房子...对于圣诞老人来说,最好的圣诞节礼物就是能够看到一点点的东西。因此,最短的提交以字节为单位获胜

排行榜

这是一个堆栈片段,可按语言生成排行榜和获胜者概述。

为确保您的答案显示出来,请使用以下Markdown模板以标题开头

## Language Name, N bytes

N是提交内容的大小(以字节为单位)

如果要在标头中包含多个数字(例如,敲击旧分数或在字节数中包含标志),只需确保实际分数是标头中的最后一个数字

## Language Name, <s>K</s> X + 2 = N bytes


我认为288应该读281:((1+0+0+1+2+3+1+0+0+0+4+1+0+0+1+2+3+2+0+0)*5+(2+0+4+0+4+0+6+0+0+0+2+1+4+3+0+3+10+0+5+0)*4=21*5+44*4=105+176=281尽管我必须说我还没有读完整的“论文”!)
Jonathan Allan

@JonathanAllan是的...我不小心花了太多时间来编写挑战...哎呀...无论如何,缺少的关键是圣诞老人的雪橇必须等待所有精灵回到船上才能搬到因此,尽管将所有数字相加并相乘可能会在某些情况下起作用,但在大多数情况下却无效。例如,有9个精灵的房子4*7要花14秒的时间(大约在引入2D地图之前的“文章”中涉及了一半),但是(4 * 5)+(7 * 4)= 48
Jojodmo

例如,有3个精灵的288值,因此他们总是必须naughty*5+nice*4在每所房子中进行全部重击,对吗?(请注意,4*7该示例中没有)
Jonathan Allan

精灵是总是总是先将煤弄掉(如您的示例所示)还是他们的排班效率高?例如,如果地图5*15存在并且有9精灵,那么(最少)要花20秒还是22秒?请参见这些文本表示,以查看该示例的说明。
乔纳森·艾伦,

对上面的编辑5*15应该阅读4*15
乔纳森·艾伦

Answers:


4

红宝石433400字节

好吧,这确实很困难,因为事实证明,精灵调度是NP困难的。

另外,请很好,这是我的第一次提交,因此我可能错过了一些明显的优化方法:

->e,h{h.split(/\+|\n/).map{|h|n,g=h.split(?*).map(&:to_i)+[0,0];return-1if(g>0&&e<2)||(n>0&&e<3);([[3,5]]*n+[[2,4]]*g).permutation.map{|j|c=[0]*e;j.map{|q|w,y=q;k=l=0;r=c.map{|x|a=b=0;c[k..e].map{|r|r<=x ?a+=1:break};(t=k+=1).times{c[t-=1]<=x ?b+=1:break};[a,b]};d=r.inject([]){|v,x|v<<l if x[0]>=w;l+=1;v}.min{|a,b|c[a]<=>c[b]};b=d-r[d][1]+1;z=c[d]+y;(b..(b+w-1)).map{|x|c[x]=z}};c.max}.min||0}.sum}

在线尝试!

我最初有更长的测试用例,但是由于我要遍历所有可能的排列安排,在某些情况下需要很长时间,因此我删除了它们。


2
欢迎来到PPCG!您的第一个答案肯定是艰难的挑战
Jo King

2

Java(OpenJDK 8),344字节

精灵的调度比我想象的要难,所以花了一些时间,而且时间很长。

尽管如此,这绝对是我最喜欢打高尔夫球的挑战!

(e,d)->{int r=0,x,y,c,p,b,g,m;for(String h:d[0].split("\\+")){d=h.split("\\*",-1);b=new Byte("0"+d[0]);g=new Byte("0"+d[1]);m=-1>>>1;for(y=1;y<=e/3&(x=(e-y*3)/2)>0;c=b/y+(b%y++<1?0:1),p=g/x+(g%x<1?0:1),x=c*5>p*4?c*5:p*4,m=x<m?x:m);for(y=0;b+g>0;b-=c,g-=p){c=e/3<b?e/3:b;x=(e-c*3)/2;p=x<g?x:g;if(c+p<1)return-1;y+=c>0?5:4;}r+=m<y?m:y;}return r;}

在线尝试所有测试!

说明;

振作起来:这是一个漫长的

    int r=0,x,y,c,p,b,g,m;               // Define all the variables I need

    for(String h:d[0].split("\\+")){     // Split houses on '+' and loop through them

        d=h.split("\\*",-1);             // Split the current house on '*' using the limit
                                         // to preserve empty strings.

        b=new Byte("0"+d[0]);            // Parse the naughty (b) and nice (g) people
        g=new Byte("0"+d[1]);

        m=-1>>>1;                        // Initialise minimum time as max integer using
                                         // overflow

        for(y=1;y<=e/3&(x=(e-y*3)/2)>0;  // For each number of elves that can concurrently
                                         // deliver coal, and still leave enough elves to
                                         // deliver presents

            c=b/y+(b%y++<1?0:1),         // Determine the number of runs needed to deliver
                                         // all coal using this number of elves

            p=g/x+(g%x<1?0:1),           // Determine the number of runs needed to deliver
                                         // all presents using this number of elves

            x=c*5>p*4?c*5:p*4,           // Get the maximum time required for the
                                         // delivery of coal or presents

            m=x<m?x:m);                  // If this is less than the current minimum time,
                                         // set it as the minimum time


        for(y=0;b+g>0;b-=c,g-=p){        // While there are still people to deliver to;

            c=e/3<b?e/3:b;               // Determine the max amount of coal to deliver

            x=(e-c*3)/2;                 // Determine how many presents can be
                                         // delivered with the remaining elves.

            p=x<g?x:g;                   // If this number is more than nice people
                                         // remaining, just use the nice people remaining

            if(c+p<1)return-1;           // If no presents can be delivered, return the
                                         // error code (-1)

            y+=c>0?5:4;                  // Increase the time by 5 if coal was
                                         // delivered, and 4 if only presents

        }                                // At the end of each loop (see above)
                                         // remove the presents and coal delivered
                                         // from the number of naughty and nice houses

        r+=m<y?m:y;                      // Increment the total time by which ever
                                         // is smaller of the calculated times
    }
    return r;                            // Return the total time

注意:这个答案取决于我对测试用例的正确性


我认为(e-y*3)/2-> e-y*3>>1保存一个字节。(最有可能也适用于(e-c*3)/2。)
乔纳森·弗雷奇

runTest("1*4",5,12);失败(您得到了"1*4", 5 elves => 13 FAILED。我惊讶于您的算法如此出色地安排了这么少的字节,因此我针对0到7的所有可能组合(精灵,顽皮和漂亮)运行了它,并发现其中一些失败了给出最佳时间。这是失败的最小组合。顺便说一句,令人难以置信的安排逻辑,很长一段时间我都不知道你是如何做到的
elyalvarado18年
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.