Oito moedas para o rei justo


22

Esta é uma "contraparte" de outro quebra-cabeça, oito moedas para o rei justo no Puzzling.SE.

Você pode ler o quebra-cabeça acima como pano de fundo. Os detalhes sobre esse quebra-cabeça são os seguintes.

Um conjunto de 8 tipos de moedas de valores diferentes é criado; o rei deseja que você descubra o N máximo, de modo que qualquer número de preço de 0 a N possa ser pago com uma combinação de não mais que 8 moedas e sem encargos.

Por exemplo, (retirado da resposta de Glorfindel). Se um conjunto de moedas dos valores 1, 2, 5, 13, 34, 89, 233, 610 for fornecido, seu programa deverá gerar 1596, porque todo número entre 0 e 1596 (inclusive) pode ser representado pela soma de não mais que de 8 números da lista fornecida (os números podem se repetir), enquanto 1597 não pode ser representado dessa maneira.

De maneira matemática, se a entrada for um conjunto S composto por 8 números inteiros positivos, a saída N desejada satisfaz que, para qualquer número n entre 0 e N, existem x1, x2, x3, ..., x8, de modo que

x1+x2+...+x8=nandx1,x2,...,x8{0}S

Seu objetivo é escrever um programa, uma função ou um trecho que aceite 8 números como entrada e gerar o máximo de N, conforme descrito acima.

Regras:

  • É permitida E / S flexível, para que seu programa possa receber a entrada da forma que for mais adequada. Você pode assumir que os números de entrada são classificados da maneira que melhor se adequar ao seu programa.
    • Por favor, indique na sua resposta se o seu programa depende da ordem de entrada
  • A entrada é um conjunto de 8 números inteiros positivos diferentes (sem zeros). A saída é um número inteiro não negativo.
    • Caso não exista 1 no conjunto de entrada, seu programa deve gerar 0 porque qualquer número de 0 a 0 satisfaz o requisito.
    • No caso de entrada inválida (o conjunto contém zero, números negativos ou duplicados), seu programa pode fazer qualquer coisa.
  • As brechas padrão são proibidas.
  • Seu programa deve ser executado dentro de alguns minutos em um computador moderno.

Casos de teste (principalmente extraídos das respostas da pergunta vinculada no Puzzling):

[1, 2, 3, 4, 5, 6, 7, 8] => 64
[2, 3, 4, 5, 6, 7, 8, 9] => 0
[1, 3, 4, 5, 6, 7, 8, 9] => 72
[1, 2, 5, 13, 34, 89, 233, 610] => 1596
[1, 5, 16, 51, 130, 332, 471, 1082] => 2721
[1, 6, 20, 75, 175, 474, 756, 785] => 3356

Este é um , portanto, o programa ou trecho mais curto em cada idioma vence!


1
Bom quebra-cabeça, mas eu pessoalmente acho que mais alguns casos de teste seriam úteis para testar nossos envios.
Sr. Xcoder

Não seria melhor tornar o tamanho da entrada um parâmetro? Abordagens de força bruta terão dificuldades com 8
Luis Mendo

1
@iBug Então, a regra usual é algo como "os envios devem ser executados em um minuto em um computador moderno". É confuso, mas geralmente bom o suficiente, porque a diferença entre a força bruta e abordagens eficientes é muito grande
Luis Mendo

1
A força bruta ainda é possível com seu limite de tempo de "alguns minutos". Uma versão ligeiramente modificada da minha resposta executa o último caso de teste em 1m20s no meu laptop de 7 anos.
nimi

1
@Arnauld Esclarecido
iBug 26/12/18

Respostas:



9

Gelatina , 12 bytes

œċⱮ8Ẏ§ṢQJƑƤS

Experimente online!

Demora em média ~ 3,7 segundos para executar todos os casos de teste no TIO no meu telefone, então, surpreendentemente, é bastante rápido.

Explicação

œċⱮ8Ẏ§ṢQJƑƤS     Monadic link / Full program.
  Ɱ8             Promote 8 to [1 ... 8] and for each value k:
œċ                    Generate all combinations of k elements from the list.
    Ẏ§           Tighten, then sum. Flatten to a 2D list then sum each.
      ṢQ         Sort the result and remove equal entries.
        JƑƤ      For each prefix of this list, return 1 if it is equal to its length range, 0 otherwise.
           S     Finally, sum the result (counts the 1's which is equivalent to what is being asked).

7

Haskell, 56 50 bytes

g c=[x|x<-[1..],all((/=x).sum)$mapM(0:)$c<$c]!!0-1

Experimente online!

Uma abordagem de força bruta. Adicione 0à lista de moedas e tente todas as combinações de 8 picaretas. Encontre o primeiro número nque não é igual à soma de nenhuma das opções e retorne n-1.

Demora cerca de 5m30s [1, 2, 5, 13, 34, 89, 233, 610]no hardware do meu laptop de 7 anos.

Edit: -6 bytes graças a @ Ørjan Johansen

Uma versão ainda mais curta (-2 bytes, novamente graças a @ Ørjan Johansen) é

Haskell, 48 bytes

g c=[x|x<-[1..],all((/=x).sum)$mapM(:0:c)c]!!0-1

mas ele usa significativamente mais memória e gera paginação pesada na minha máquina e não termina "dentro de alguns minutos".


1
Você pode usar mapM(0:)$c<$c. (De fato, mapM(:0:c)cdeve funcionar, mas o tempo limite é excedido no TIO para o caso de teste especificado.) #
Ørjan Johansen

4

Geléia , 9 bytes

Żœċ8§ḟ’$Ṃ

Experimente online!

Como funciona

Żœċ8§ḟ’$Ṃ  Main link. Argument: A (array)

Ż          Prepend a 0 to A.
 œċ8       Take all combinations of length 8, with repetitions.
    §      Take the sum of each combination.
       $   Combine the two links to the left into a monadic chain.
      ’      Decrement all sums.
     ḟ       Filterfalse; keep only sums that do not appear in the decremented sums.
        Ṃ  Take the minimum.

2
Żṗ8§ḟ’$Ṃeconomiza um byte, mas não tenho certeza se 8,5 minutos contam como poucos .
Dennis


4

JavaScript (ES6),  100 88 80  76 bytes

Trata-se essencialmente de uma busca por força bruta, mas aprimorada com a poda para acelerar. O tempo médio de execução para os casos de teste é próximo a 1 segundo no TIO.

Supõe que a matriz de entrada seja classificada da maior para a menor.

a=>[...Array(a[0]*9)].findIndex(g=(i=8,s)=>s*i>0?a.every(x=>g(i-1,s-x)):s)-1

Experimente online!

Comentado

a =>                      // a[] = input array
  [...Array(a[0] * 9)]    // create an array of 9 * max(a) entries
  .findIndex(             // find the position of the first truthy result
    g = (i = 8, s) =>     // g = recursive function taking a counter i, initialized to 8
                          //     and a sum s, initialized to the position in the above array
      s * i > 0 ?         //   if s is positive and i is not equal to 0:
        a.every(x =>      //     for each value x in a[]:
          g(i - 1, s - x) //       do a recursive call with i - 1 and s - x
        )                 //     end of every()
      :                   //   else:
        s                 //     yield s (s = 0 means success and makes findIndex go on)
  ) - 1                   // end of findIndex(); decrement the result


3

Pari / GP , 57 bytes

a->n=-1;while(polcoeff((1+sum(i=1,8,x^a[i]))^8,n++),);n-1

Experimente online!


isso está usando a função de geração?
don bright

1
@donbright Sim.
alephalpha

1
isso é incrível .. uma das poucas respostas que não impõe brutalidade à solução. muitas linguagens provavelmente não possuem recursos simbólicos polinomiais. Pari GP é legal.
don bright

2

Python 2 , 125 115 111 bytes

lambda c:sum(i==j for i,j in enumerate(sorted(set(map(sum,product([0]+c,repeat=8))))))-1
from itertools import*

Experimente online!

Espera uma lista de números inteiros como entrada.

Explicação:

# an anonymous function
lambda c:
                                                          # get all length-8 combinations of values, from (0,0,0,0,0,0,0,0) to (8,8,8,8,8,8,8,8)
                                                          # zero is added to ensure that combinations of fewer than 8 coins are represented Ex:(1,0,0,0,0,0,0,0)
                                                          product([0]+c,repeat=8)
                                                  # for each combination, sum the values
                                                  map(sum,.......................)
                                       # get unique values, then sort them smallest to largest
                                       sorted(set(................................))
             # for each index, value pair, return if the index is equal to the value
             i==j for i,j in enumerate(.............................................)
         # in Python arithmetic, False is 0 and True is 1. So, count how many items match their index.
         # Since zero was added to the list, there will always be one extra match (0==0). So offset by one.
         sum(........................................................................)-1
from itertools import*

2

Perl6, 65 63 41 bytes ( 39 37 caracteres)

{@_=(0,|@_)X+(0,|@_)for ^3;($_ if $_==$++for @_.sort.unique)-1}

Experimente online!

Este é um bloco anônimo que recebe seus dados como uma matriz. A (0,|@_)é uma maneira rápida de adicionar um 0a @_, e mesmo que ele é feito duas vezes, ainda é um pouco mais curto do que @_.push: 0;o que seria, então precisam de espaços após a _. Esta é uma abordagem de força bruta que combina um pouco com o fato de serem 8 combinações. Após a adição cruzada, uma lista anônima é criada para valores seqüenciais. Com operadores matemáticos, as listas são avaliadas de acordo com seu comprimento; portanto, o -1 exerce dupla tarefa: contabilizando o 0 e coagindo ao Int.

Isso pode levar um tempo agradável, mas alterando um ou ambos (0,|@_)para (0,|@_.unique)antes do primeiro for, pode ser acelerado consideravelmente. Isso adiciona +7 (tempo de execução <60s) ou +14 (tempo de execução <10s) à pontuação, se você sentir que o primeiro está muito lento (eu fiz isso no código vinculado para evitar tempos limite após 60 segundos).

Editar: Juntar nos comentários melhorou (mesma ideia, adição cruzada e, em seguida, retorne o último resultado consecutivo) a um impressionante número de 39 caracteres (41 bytes):

{(@_=@_ X+0,|@_)xx 3;first *+1@_,^∞}

Experimente online!

A tabulação final não precisa de um 0, economizando alguns bytes, basta adicionar 0 de uma vez. Os xx 3imita o loop (ainda queijos nas moedas sendo uma potência de 2). O firstsub retorna o primeiro número na lista infinita 0..*(também ^Infé possível, mas não economiza espaço), que +1não é membro da lista de adição cruzada. Como o meu, é lento, então adicione +7 para um uniqueapós o primeiro igual, se você achar que é muito lento para orientações.


1
48 bytes . Tecnicamente, o uniquenão é necessário, mas o acelera muito #
Jo King

@JoKing agradável, eu não sei por que não pensei em usar xx. Eu sabia que tinha que haver uma maneira de fazer a tabulação final de uma maneira muito mais curta, usando funções definidas, mas meu cérebro não estava funcionando.
user0721090601

O que xx 1deveria serxx 3
Jo King

@JoKing Fixed. Também percebi dois caracteres (mas sem bytes) podem ser salvos usando^∞
user0721090601

Na verdade, você pode salvar alguns bytes em (1...*∉@_)-1vez de usar first(o que eu sei que é o mesmo método que usei aqui )
Jo King

1

JavaScript (Node.js) , 171 145 115 bytes

f=(s,n=3)=>n?f(s=new Set(a=[0,...s]),n-1,a.map(m=>a.map(n=>s.add(m+n)))):Math.min(...[...s].filter(m=>!s.has(m+1)))

Experimente online! Porta da resposta Python 3 de @ Mark. 108 bytes no Firefox 30-57:

f=(s,n=3)=>n?f(new Set((for(n of s=[0,...s])for(m of s)n+m)),n-1):Math.min(...[...s].filter(m=>!s.has(m+1)))

1

Wolfram Language (Mathematica) , 46 bytes

0//.x_/;Min[Tr/@FrobeniusSolve[#,x+1]]<9:>x+1&

Experimente online!

Abordagem de força bruta: verifica números inteiros contando para cima até atingir um valor que não pode ser pago em 8 moedas. Muito, muito lento (tempo limite esgotado), mas tenho certeza de que a condição está correta.


0

Limpo , 161 bytes

import StdEnv,Data.List
$l=:[1:_]#k=sort(nub(map sum(iter 8(concatMap(\[h:t]=[[e,h:t]\\e<-[0:l]|e>=h]))[[0]])))
=length(takeWhile((>=)1)(zipWith(-)(tl k)k))
$_=0

Experimente online!

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.