Segmentos de linhas de números romanos

10

Escreva um programa ou função que aceite um número inteiro no intervalo 1..3999 como entrada e retorne o número de segmentos de linha necessários para expressar esse número inteiro em números romanos padrão (para usar XL, mas não VM). Exemplos:

   1 -> 1
   4 -> 3
   5 -> 2
   9 -> 3
  10 -> 2
  40 -> 4
  50 -> 2
  90 -> 3
 100 -> 1
 400 -> 3
 500 -> 2
 900 -> 5
1000 -> 4

Construções de conversão de número romano são permitidas, mas você pode resolver o problema sem elas subtraindo repetidamente o maior número restante da lista acima. Exemplo: 1234 = 4 + 1 + 1 + 2 + 2 + 2 + 3 = 15.

Isso é , então o programa mais curto vence.

Neil
fonte
Por que 10 segmentos de duas linhas são substituídos por quatro? Ao escrever X, você normalmente escreve apenas duas linhas, mas a interseção das linhas não o torna em quatro segmentos?
Alex A.
@AlexA. A definição de segmento de linha é geralmente algo como: "O conjunto de pontos após o caminho mais curto entre dois pontos". Não parece haver nenhuma razão para cortar o X com base nisso, você só precisa de dois conjuntos de pontos finais para defini-lo. (Assumindo Romanos escreveu principalmente sobre geometrias euclidianas, eu acho)
FryAmTheEggman
@FryAmTheEggman Hm okay. É bom saber, obrigado.
Alex A.

Respostas:

2

Pitão, 92 76 70 bytes

KsMc."/9hæ²z³Þ§ªW×Oû[Tnè,O¤"\/WQ=Q-Q=Nef!>TQ%2K aY@KhxKN;sY

Experimente aqui!

Obrigado a @FryAmTheEggman por algumas sugestões de empilhamento de strings que me salvaram alguns bytes!

Ainda estou me perguntando se existe uma maneira matemática de codificar esta lista. Vai tentar descobrir alguma coisa.

Explicação

Isso usa o algoritmo fornecido. Kcontém a lista fornecida com os números e o número correspondente a corrosão dos segmentos de linha em alternância. Essa lista é construída dividindo uma sequência compactada, que é decodificada para 0/0/1/1/4/3/5/2/9/3/10/2/40/4/50/2/90/3/100/1/400/3/500/2/900/5/1000/4, /e mapeando cada elemento para um número inteiro.

KsMc. "..." \ / WQ = QQ = Nef!> TQ% 2K aY @ KhxKN; sY # Q = entrada

   c. "..." \ / # divide a string em /
KsM # mapeia todos os números para int e atribui a K
            WQ # enquanto Q! = 0
                     f% 2K # apenas pegue cada segundo elemento de K e filtre com T
                      !> TQ # T <= Q
                  = Ne # Pegue o último elemento disso e atribua-o a N
              = QQ # Q = Q - N
                                   xKN # índice da primeira ocorrência de N em K
                                  h # incrementa esse índice porque queremos os segmentos de linha
                              aA @ K # obtém o segmento de linha desse índice e anexa a Y
                                      ; sY # finaliza o loop e imprime a soma de todos os segmentos de linha em Y
Denker
fonte
3

C, 148 129 caracteres

d,x,n[]={1000,900,500,400,100,90,50,40,10,9,5,4,1,4,5,2,3,1,3,2,4,2,3,2,3,1};f(c){while(d+=(c/n[x])*n[x+13],c%=n[x++]);return d;}

Meu primeiro código-golfe: ^). Como a pergunta indica que posso usar uma função, mudei main para uma função para aparar alguns caracteres (o mais importante: pass c como parâmetro, em vez de scanf)

desempacotado

d,x,n[]={1000,900,500,400,100,90,50,40,10,9,5,4,1,4,5,2,3,1,3,2,4,2,3,2,3,1};
f(c){
  while(d+=(c/n[x])*n[x+13],
        c%=n[x++]);
  return d;
}
STDQ
fonte
2

Mathematica, 80 72 bytes

Tr[Characters[#~IntegerString~"Roman"]/.{"I"|"C"->1,"M"->4,_String->2}]&

Função anônima que apenas converte números em algarismos romanos, substitui cada caractere pelo número de segmentos e recebe o total.

LegionMammal978
fonte
2

Retina, 128 bytes

. +
$ *
1 {1000}
t '
1 {900}
td
1 {500}
d
1 {400}
t
1 {100}
"
1 {90}
t
1 {50}
d
1 {40}
t '
1 {10}
d
1 {9}
t
1 {5}
d
1 {4}
t
1 1
"
t
d '
d
''
'+
$ .0

Substituição simples até que não haja mais nada para substituir. Então os apóstrofos são contados e esse é o nosso número de segmentos de linha.

Se entrada e saída em unário são permitidas, são 115 bytes (embora quem queira digitar 1234?).

Experimente online!
Experimente online! (IO unário)

daavko
fonte
2

Python 3, 95 bytes

def f(a,b=0):
 for e in'᝴ᔝ஺ॣəȟĮô>9 ':e=ord(e);d=e//6;b+=a//d*(e%6);a%=d
 return b

A cadeia Unicode consiste nos pontos de código:

6004 5405 3002 2403 601 543 302 244 62 57 32 27 7
Lynn
fonte
Se você transformar essa string em um literal de bytes, poderá omitire=ord(e);
xsot 20/03
Eu não acho que isso funcione no meu caso. Eu preciso de uma seqüência de caracteres Unicode :( ou seja, eu estou looping sobre os codepoints em que seqüência, não sobre os bytes.
Lynn
11
Ah eu vejo. Você se importa de fornecer um hex hexadecimal da string? Não é exibido corretamente no meu telefone.
Xsot #
1

Java, 152 bytes

Porque, você sabe, Java.

n->{int c=0;int[]r={999,4,899,5,499,2,399,3,99,1,89,3,49,2,39,4,9,2,8,3,4,2,3,3,0,1};for(int i=0;i<26;i+=2)while(n>r[i]){n-=r[i]+1;c+=r[i+1];}return c;}

Implementação literal simples do algoritmo fornecido. A matriz compacta as informações da transformação: os índices pares são um a menos que o número romano e os índices ímpares são a contagem desse número.

Este é um lambda que pega e retorna um int/ Integer. Isso inclui IntUnaryOperatorou UnaryOperator<Integer>.

CAD97
fonte
1

JavaScript (ES6), 79 bytes

n=>"0123323453"[[,a,b,c,d]=1e4+n+'',d]-(-"0246424683"[c]-"0123323455"[b])+a*4

As cadeias representam o número de segmentos de linha para as unidades, dezenas e centenas de dígitos. (Milhares é simplesmente quatro vezes o dígito de milhares.) Esse método parece ser mais curto que outras opções, como o algoritmo sugerido na pergunta.

Editar: salvou 2 bytes graças a @ user81655.

Neil
fonte
Este é um algoritmo legal. Reorganizar os lançamentos também pode salvar 2 bytes:n=>"0123323453"[[,a,b,c,d]=1e4+n+'',d]-(-"0246424683"[c]-"0123323455"[b])+a*4
user81655
@ user81655 Ah, isso é legal: basta alterar os +s para -s para remover o líder +, mas o agrupamento salva outro byte.
194 Neil