Calcular o pedágio de troll para passar com segurança

12

Inspirado em /puzzling//q/626


Nas suas aventuras, você chega a uma série de 7 pontes que precisa atravessar. Debaixo de cada ponte vive um troll. Para atravessar a ponte, você deve primeiro dar ao troll um número de bolos como uma porcentagem do número de bolos que você está carregando. Por serem trolls gentis, eles devolvem um certo número de bolos a você.

No início de cada dia, o rei dos trolls locais define o percentual de imposto sobre bolos que cada viajante deve pagar e o reembolso do bolo - o número de bolos que cada troll deve devolver aos viajantes.

Seu trabalho é calcular o número mínimo de bolos necessários para passar pelas 7 pontes de trolls para as condições especificadas naquele dia.

Presumir:

  1. Dois parâmetros de entrada: porcentagem de imposto sobre bolos (número inteiro de 0 a 100) e reembolso do bolo de pesca à corrica.
  2. Ninguém, nem mesmo os trolls, quer um bolo parcialmente comido por outro troll. Se você ficar com uma fração de bolo, o troll o pega.
  3. Se um troll aceita um imposto de bolo, mas precisa devolver todos os bolos (fica com o mesmo ou menos bolos do que antes), ele fica com raiva e come você e seus bolos.
  4. Todo troll deve manter pelo menos um bolo completo.
  5. Você só pode carregar no máximo 100 bolos.
  6. Você precisa terminar o dia em que está atualmente ou do outro lado das 7 pontes.

Desafio:

Escreva um programa completo para gerar o número mínimo de bolos para viajar para o dia atual ou zero, se não for possível viajar com segurança hoje - você esperará para ver quais são os números amanhã.

A entrada deve ser passada como stdin, argumentos de linha de comando ou entrada de arquivo.

O código mais curto (contagem de bytes) vence.

Exemplo:

25% de imposto sobre o bolo, reembolso de 2 trolls.

comece com 19 bolos
antes do troll 1: (19 * 0,75) = 14,25
após o troll 1: (14 + 2) = 16

antes do troll 2: (16 * 0,75) = 12
após troll 2: (12 + 2) = 14

etc.

19 bolos -> 16 -> 14 -> 12 -> 11 -> 10 -> 9 -> 8
18 bolos -> 15 -> 13 -> 11 -> 10 -> 9 -> 8 -> 8 (regra 3)

Para 18 bolos, o último troll não conseguiria manter nenhum bolo. Portanto, o número mínimo de bolos para um dia de 25% / 2 é 19.

input: 25 2
output: 19

Exemplo 2:

90% de imposto sobre bolo, 1 reembolso para bolo troll

100 bolos -> 11 -> 2 -> 1 (regra 4)

O terceiro troll não conseguiu ficar com nenhum bolo. Portanto, não é possível viajar em um dia de 90% / 1, mesmo começando com o número máximo de bolos.

input: 90 1
output: 0

Dados

Faça um gráfico rápido dos valores de entrada e saída. Fiquei surpreso que isso não era "suave" (como uma curva de sino ou similar); existem várias ilhas visíveis.

gráfico de dados

Dados para os interessados. As colunas são divididas em intervalos de 5%, as linhas são unidades de 1 intervalo de reembolso de bolo (o Excel girou a imagem). Você pode ver que não pode haver um reembolso superior a 28 bolos.

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
Comunidade
fonte
Bom ponto. Torne-o um programa completo para simplificar. A entrada pode ser especificada da maneira que você achar melhor, desde que não seja codificado (desafio atualizado).
Este é um bom quebra-cabeça para força bruta no CJam. Eu vou fazer isso amanhã
bah, é por isso que c # não pode ter coisas agradáveis
A regra 2 parece excluir a possibilidade de um troll receber apenas uma fração de um bolo, o que deve tornar a suposição 4 redundante. No entanto, você diz no exemplo 2 que o terceiro troll receberia apenas 0,8 bolos.
Dennis
Existem conflitos nas especificações. No 25 2caso de 11 bolos, você dá ao troll 2,75 bolos e recupera 2, para que o troll mantenha 0,75 (+ 25) e você sobreviva. No 90 1caso dos 2 bolos, você dá 1,8 ao troll e recebe 1 de volta, para que o troll fique com 0,8 (+. 2), mas você morre.
TwiNight

Respostas:

6

CJam, 46 43 41 39 38 36 33 bytes

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

Entrada via ARGV.

Existe um intérprete online, mas infelizmente ele não suporta argumentos de linha de comando. Para testar, você pode imitá-lo no STDIN com esta versão:

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

Explicação da versão baseada em 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.";

O conteúdo da pilha é impresso automaticamente no final do programa.

Martin Ender
fonte
Seu código produz resultados incorretos para 55 2(em 0vez de 100) e 56 5(em 98vez de 94). Isso ocorre 100_0.55*-ie é 25_0.56*-ivítima de imprecisão de ponto flutuante. Até onde eu sei, os pares também 31 24, 31 25, 33 21, 33 22, 33 23, 35 10, 35 12, 35 15, 35 16, 35 27, 56 1, 57 4dão resultados incorretos.
Dennis
1
@Dennis corrigido, obrigado!
Martin Ender
@ Dennis Isso realmente salvou um byte. Eu gostaria que o CJam tivesse encerramentos, então eu poderia apenas definir um bloco no início que faça a dedução de imposto e usá-lo, em vez de usar duas variáveis. Talvez eu possa salvar algo usando ARGV em vez de STDIN, deixe-me ver.
Martin Ender
5

CJam, 44 40 38 37 35 bytes

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

Ou ao usar argumentos e {}#truques de linha de comando , 33 bytes :

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

Não colocar este como meu principal como {}#abordagem é inspirado na resposta de Martin.

Exemplo de execução:

Entrada:

25 2

Resultado:

19

Outro:

Entrada:

15 14

Resultado:

100

Como funciona

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";

Experimente online aqui

Optimizer
fonte
E agora resta esperar Dennis aparecer e vencer a nós dois. ;)
Martin Ender
Não está em CJam;) (esperançosamente)
Otimizador
Eu realmente gosto do ]W=truque, mas até agora, de todas as formas que tento usá-lo, acabo com a mesma contagem de caracteres.
Martin Ender
@ MartinBüttner - Sim, eu também.
Optimizer
1
@ Dennis - deve funcionar agora, com um benefício adicional de 2 bytes código mais curto: D
Optimizer
4

APL (39)

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

Explicação:

  • T R←⎕: leia dois números do teclado e armazene-os em T(imposto) e R(retorno).
  • Z←⍳M←100: armazene o número 100em Me todos os números de 1a 100em Z.
  • {... }⍣7¨: para cada elemento Z, execute a seguinte função 7 vezes:
    • R+⌊1-T÷M: calcule quantos bolos precisam ser pagos,
    • ⍵(⊢×>): multiplique esse valor por 1 se o troll acabar com mais bolo do que ele começou, ou por 0 se não.
  • ⊃Z/⍨: para cada elemento Z, replique-o pelo número que essa função forneceu. (Portanto, todos os números para os quais a função retornou 0desaparecem.) Em seguida, selecione o primeiro item dessa lista. Se a lista acabou vazia, isso dá 0.
marinus
fonte
3

C, 83 bytes

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;
}

Se funcionar, funciona para todos os possíveis startcakes, não apenas de 1 a 100.

EDIT: Funciona. Golfe:

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;}

Com o limite máximo de 100 bolos:

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 bytes.

Gerwin
fonte
Eu acho que é uma parte importante das especificações que a solução retorne zero se você precisar de mais de 100 bolos no início.
Martin Ender
2

CJam, 36 bytes

q~:R100:H*\d:T/i){R-H*HT-/m]}6*_H)<*
Dennis
fonte
1

C ++ - 202 caracteres

Como sempre, meu C ++ fez o pior:

#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;}

fonte
1

APL, 36

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

Explicação

Observe que existe um "limite de bolo". Para taxa de imposto xe reembolso y, você precisará estritamente de mais de y÷xbolos para passar pela próxima ponte.

x y←⎕pegue entrada e atribua a x(imposto) e y(retorno)
⍳x÷←100divida xpor 100 e gere uma matriz de 1 a 100

{y+⍵-⌈⍵×x}⍣6chame a função "passar ponte" 6 vezes:
⌈⍵×xo número de bolos que você tem, a taxa de imposto, arredondar para cima (o valor que você paga)
⍵-Subtrair do número de bolos que você tem
y+Adicionar o reembolso

Em seguida, você obtém uma matriz de 100 elementos mostrando o número de bolos restantes após atravessar 6 pontes, se você começar com 1 a 100 bolos. Para ver se você pode atravessar a última ponte, verifique se você está acima do limite y÷x. Como alternativa:
multiplique a matriz x
y<verificando se maior quey

Por fim,
1⍳⍨encontre o índice da primeira ocorrência de 1(true), retorna 101se não for encontrado
101|mod 101

TwiNight
fonte
1

C 128

Muito parecido com a outra solução C, mas acho que é inevitável. O principal truque é romper o loop interno com valores diferentes, dependendo se ele está completo ou não. Isso me permite usar?: Quando não podia, se usava 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);} 

Ungolfed

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);
}
Alquimista
fonte
Qual compilador você está usando?