计算巨魔通行费以安全通过


12

/puzzling//q/626启发


在您的冒险旅程中,您会到达一系列必须跨越的7座桥梁。每座桥下都有一个巨魔。为了过桥,您必须首先为巨魔提供一定数量的蛋糕,占所携带蛋糕的百分比。因为这些都是善意的巨魔,所以它们会把一定数量的蛋糕还给您。

每天开始时,当地巨魔国王设置每个旅行者必须支付的蛋糕税百分比,然后将巨魔蛋糕退款-每个巨魔必须退还给旅行者的蛋糕数量。

您的工作是计算当天在给定条件下通过所有7个巨魔桥所需的最少蛋糕数量。

假设:

  1. 输入两个参数:蛋糕税百分比(0到100之间的整数)和巨魔蛋糕退款。
  2. 没有人,甚至没有巨魔,都想要被另一只巨魔部分吃掉的蛋糕。如果剩下的只是一块蛋糕,那么巨魔就会得到它。
  3. 如果一个巨魔接受了蛋糕税,但是又不得不把所有蛋糕还给你(剩下的蛋糕比以前少或少),它就会生气并吃掉你和你的蛋糕。
  4. 每个巨魔必须至少保留一个完整的蛋糕。
  5. 您最多只能携带100个蛋糕。
  6. 您需要结束当前所在的日子或所有7座桥梁的另一端。

挑战:

编写一个完整的程序以输出当天要行驶的最小蛋糕数,如果今天不能安全行驶,则输出零个蛋糕-您将等待观察明天的数字。

输入应作为标准输入,命令行参数或文件输入传递。

最短的代码(字节数)获胜。

例:

蛋糕税25%,巨魔蛋糕退还2。


巨魔1:(19 * 0.75)= 14.25
巨魔1:(14 + 2)= 16之后开始

巨魔2之前:(16 * 0.75)= 12
巨魔2之后:(12 + 2)= 14

等等

19个蛋糕-> 16-> 14-> 12-> 11-> 10-> 9-> 8
18个蛋糕-> 15-> 13-> 11-> 10-> 9-> 8-> 8(规则3)

对于18个蛋糕,最后一个巨魔将无法保留任何蛋糕。因此,25%/ 2天的最少蛋糕数量为19。

input: 25 2
output: 19

范例2:

90%蛋糕税,1个巨魔蛋糕退款

100个蛋糕-> 11-> 2-> 1(规则4)

第三只巨魔没有留下任何蛋糕。因此,即使从最大数量的蛋糕开始,也不可能在90%/ 1天的行程中旅行。

input: 90 1
output: 0

数据

汇总输入和输出值的快速图形。我很惊讶这不是“平滑的”(像钟形曲线或类似曲线);有几个引人注目的岛屿。

数据图表

那些感兴趣的数据。列分为5%的间隔,行是1个蛋糕退款间隔的单位(擅长旋转图像)。您会发现不能退款超过28个蛋糕。

27, 17, 13, 14, 15, 18, 20, 24, 53, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
47, 27, 20, 19, 19, 19, 24, 39, 48, 68, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0
67, 37, 28, 24, 23, 28, 27, 29, 50, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
87, 47, 33, 29, 27, 28, 31, 44, 37, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 57, 40, 34, 31, 29, 34, 34, 62, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 67, 48, 39, 35, 38, 37, 49, 57, 76, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 77, 53, 44, 39, 38, 47, 39, 59, 78, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 87, 60, 49, 43, 39, 40, 54, 46, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 97, 68, 54, 47, 48, 44, 44, 71, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 73, 59, 51, 48, 47, 59, 73, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 80, 64, 55, 49, 51, 49, 68, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 88, 69, 59, 58, 54, 64, 70, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 93, 74, 63, 58, 57, 54, 57, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 100, 79, 67, 59, 67, 69, 82, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 84, 71, 68, 60, 59, 77, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 89, 75, 68, 64, 74, 79, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 94, 79, 69, 67, 64, 66, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 99, 83, 78, 71, 79, 91, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 87, 78, 74, 69, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 91, 79, 77, 84, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 95, 88, 87, 74, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 99, 88, 80, 89, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 89, 84, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 98, 87, 94, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 98, 91, 84, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 99, 94, 99, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 97, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

好点子。为了简单起见,使其成为一个完整的程序。可以指定输入,但是只要您不对其进行硬编码(更新的质询),就可以认为合适。

这对于CJam中的暴力破解是一个很好的难题。我明天左右去做

h,这就是为什么C#不能拥有美好的事物

规则2似乎排除了巨魔只接收一小部分蛋糕的可能性,这应该使假设4变得多余。但是,您在示例2中说,第三个巨魔只会得到0.8个蛋糕。
丹尼斯

规格中有冲突。在25 211个蛋糕的情况下,您给巨魔2.75个蛋糕并取回2个,因此巨魔保持.75(+。25),您就可以生存。在90 12块蛋糕的情况下,您给巨魔1.8并取回1,因此巨魔保持0.8(+。2),但您死了。
TwiNight

Answers:


6

CJam,46 43 41 39 38 36 33字节

100:H,{)_7{ea:i~H@m2$*H/+@;}*>}#)

通过ARGV输入。

有一个在线解释器,但是不幸的是它不支持命令行参数。为了进行测试,您可以使用以下版本从STDIN中对其进行模仿:

rr]:A;
100:H,{)_7{A:i~H@m2$*H/+@;}*>}#)

基于ARGV的版本的说明:

100:H                                  "Push a 100 and save it in H.";
     ,                                 "Create a range (as an array) from 0 to 99.";
      {                       }#       "Find the first index in [0,1,2,...,99] for which the
                                        block produces a truthy (non-zero) value.";
       )_                              "Increment and duplicate the current array element.";
         7{                }*          "Execute the block seven times.";
           ea:i                        "Push the command-line arguments as an array of strings
                                        and convert each element to an integer";
               ~                       "Unwrap the array.";
                H@                     "Push a 100 and rotate the stack to pull up
                                        the first command line argument.";
                  m                    "Subtract (from 100).";
                   2$                  "Copy the last iterations result.";
                     *H/               "Multiply and divide by 100, deducting tax.";
                        +              "Add the refund.";
                         @;            "Rotate top three stack elements, and discard the one that 
                                        has been pulled to the top. This always leaves the last 
                                        two results on the stack.";

                             >         "Make sure that the last result was less than the second 
                                        to last. Yields 0 or 1.";
                                )      "After the # search completes, we'll get -1 if no such 
                                        index exists, or one less than the desired number if it 
                                        does, so we can just increment.";

堆栈中的内容将在程序末尾自动打印。


您的代码为55 20而不是100)和56 598而不是94)产生了错误的结果。这是因为100_0.55*-i25_0.56*-i浮点不精确性有关。据我所知,这两个配对31 24, 31 25, 33 21, 33 22, 33 23, 35 10, 35 12, 35 15, 35 16, 35 27, 56 1, 57 4也会给出错误的结果。
丹尼斯

1
@丹尼斯修复,谢谢!
马丁·恩德2014年

@Dennis实际上节省了一个字节。我希望CJam有闭包,然后我可以在开始时定义一个块进行减税,并使用它,而不是使用两个变量。让我看看,也许我可以使用ARGV代替STDIN来保存一些内容。
Martin Ender 2014年

5

CJam,44 40 38 37 35字节

l~U100:M),{{_M5$-*M/3$+_@<*}7*}=]W=

或者,当使用命令行参数和 {}#技巧时,为33个字节

100:M,{){_ea:i~M@-@*M/+_@<*}7*}#)

{}#马丁的回答启发了我,不要把这作为我的主要方法。

示例运行:

输入:

25 2

输出:

19

另一个:

输入:

15 14

输出:

100

怎么运行的

l~                       "Read the two numbers, swap and convert tax to double";
  U100:M),               "Push 0 and [0, 1, ... 100] to stack, storing 100 in M";
          {  ...  }=     "Run this code for each element until top stack element is 1";
           {...}7*       "Run this code block 7 times";
_                        "Copy the array element";
  M5$                    "Push 100 and a copy tax % to stack";
     -*                  "Number = (100 - tax %) * Number";
       M/                "Integer divide the number by 100";          
         3$+             "Add refund";
            _@<*         "Convert to 0 if refunded number > before tax one";
                    ]W=  "Take the last element of the stack";

在这里在线尝试


现在剩下的就是等待丹尼斯来打败我们俩。;)
Martin Ender 2014年

不在CJam中;)(希望)
Optimizer

我真的很喜欢这个]W=技巧,但是到目前为止,我尝试使用它的每种方式最终都得到了相同的字符数。
Martin Ender 2014年

@MartinBüttner-是的,我也是。
Optimizer

1
@Dennis-现在应该工作,附加的好处是缩短了2个字节的代码:D
Optimizer

4

APL(39)

T R←⎕⋄⊃Z/⍨{⍵(⊢×>)R+⌊⍵×1-T÷M}⍣7¨Z←⍳M←100

说明:

  • T R←⎕:从键盘上读取两个数字,并将它们存储在T(税)和R(返回)中。
  • Z←⍳M←100:将数字存储在100M,并将所有数字存储在1100Z
  • {... }⍣7¨:对于中的每个元素Z,请运行以下函数7次:
    • R+⌊1-T÷M:计算需要支付多少蛋糕,
    • ⍵(⊢×>):如果巨魔结出的蛋糕多于开始的数量,则将其乘以1;否则,将其乘以0。
  • ⊃Z/⍨:对于中的每个元素Z,请按该函数给出的编号进行复制。(因此,函数返回的所有数字都会0消失。)然后从该列表中选择第一项。如果列表最后为空,则给出0

3

C,83字节

int cake(int perc_taken, int given_back)
{
    int startcake = floor(100.f/perc_taken*given_back+1);
    for(int i = 0; i < 6; i++)
    {
        startcake = ceil((startcake-given_back) * 100.f/(100 - perc_taken));
    }
    return startcake;
}

如果可行,它将适用于所有可能的起始蛋糕,而不仅仅是1到100。

编辑:它有效。打高尔夫球:

n(int p,int g) {int s=100./p*g+1,i=0;for(;i++<6;){s=ceil((s-g)*100./(100-p));}return s;}

上限为“ 100个蛋糕”:

n(int p,int g) {int s=100./p*g+1,i=0;for(;i++<6;){s=ceil((s-g)*100./(100-p));}return s>100?0:s;}

91个字节。


我认为,如果您一开始需要超过100个蛋糕,则解决方案将返回零,这是规范的重要组成部分。
马丁·恩德


1

C ++-202个字符

和往常一样,我的C ++做得最糟:

#include<iostream>
int main(){double p,g,c=1,i,r,t;std::cin>>p>>g;for(;c<101;c++){r=c;for(i=0;i<7;i++){t=(int)(r*(1-(p/100))+g);if(t>=r){r=-1;break;}r=t;}if(r!=-1)break;}r!=-1?std::cout<<c:std::cout<<0;}

1

APL,36

x y←⎕⋄101|1⍳⍨y<x×{y+⍵-⌈⍵×x}⍣6⍳x÷←100

说明

请注意,有一个“蛋糕阈值”。对于税率x和退款yy÷x通过下一座桥梁,您将需要的不仅仅是蛋糕。

x y←⎕接受输入并分配给x(tax)和y(return)
⍳x÷←100除以x100,然后生成一个1到100的数组

{y+⍵-⌈⍵×x}⍣6调用“过桥”功能6次:
⌈⍵×x您拥有的蛋糕数量,税率乘以四舍五入(您支付的金额)
⍵-从您拥有的蛋糕数量中减去
y+添加退款

然后,如果您以1〜100个蛋糕为起点,则得到一个100个元素的数组,显示经过6个桥后剩下的蛋糕数。要查看是否可以越过最后一座桥,请检查您是否超过阈值y÷x。或者:
将数组乘以x
y<检查是否大于y

最后,
1⍳⍨找到第一次出现的索引1(true),101如果找不到则返回
101|mod 101


1

C 128

与其他C解决方案非常相似,但我认为这是不可避免的。主要技巧是根据是否要完成而用不同的值突破内部循环。这使我可以使用?:如果我无法使用break,则无法使用;

t,r,j,k,l,p;main(i){for(scanf("%d%d",&t,&r),i=101;k=--i;){for(j=8;--j>0;)(p=r+k*(100-t)/100)<k?k=p:j=0;j?0:l=i;}printf("%d",l);} 

不打高尔夫球

int t,r,j,k,l,p;
main(int i)
{
    for(scanf("%d%d",&t,&r),i=101;k=--i;)
    {
        for(j=8;--j>0;)
        {
            if((p=r+k*(100-t)/100)<k)
                k=p;
            else
                j=0;
        }
        j?0:l=i;
    }
    printf("%d",l);
}

您正在使用什么编译器?
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.