Converti i numeri romani cifrati in decimali arabi


16

Scrivi un algoritmo per interpretare una sequenza di lettere come un numero romano. (vedi le regole numerali romane di seguito)

Ogni lettera distinta ha un valore decimale arabo corrispondente, nessun massimo. Ma non hai la chiave in anticipo, quindi {A=10, I=1, X=5, ... Z=1000000}è deciso dalla tua interpretazione.

Sfida

  1. Leggi input via STDINo equivalente e scrivi output via STDOUTo equivalente
  2. Gli input validi sono combinazioni di lettere maiuscole e minuscole, ovvero la corrispondenza \[a-zA-Z]+\
  3. L'immissione deve essere convalidata per vedere se la sequenza di lettere può essere interpretata come un numero romano valido
  4. Se l'input supera la convalida, l'output valido deve essere l'interpretazione decimale araba più bassa e la chiave utilizzata, ovvero Aaviene interpretata come 4 {a=5, A=1} no 6 {A=5, a=1} o 9 {a=10, a=1}

Regole numerali romane

  1. Solo le lettere che rappresentano poteri di dieci possono essere ripetute, un massimo di tre volte consecutive e quattro volte in totale, ad es II III XXXIX

  2. Se una o più lettere vengono inserite dopo un'altra lettera di valore maggiore, aggiungi tale importo

    AAaa   => 22 {A=10, a=1}          (20 + 2 = 22)  
    bbAAaa => 222 {b=100, A=10, a=1}  (200 + 20 + 2 = 222)   
    
  3. Se una lettera viene posta prima di un'altra lettera di valore maggiore, sottrarre tale importo

    Aa    => 4 {a=5, A=1}                 (5 – 1 = 4)  
    AaA   => 19 {A=10, a=1}               (10 + 10 – 1 = 19)  
    BbBaA => 194 {B=100, b=10, A=5, a=1}  (100 + 100 - 10 + 5 - 1 = 194)  
    

    Diverse regole si applicano per sottrarre importi da numeri romani:

    • Sottrarre solo poteri di dieci cioè 1, 10, 100... no 5, 50, 500...
    • Nessun doppia sottrazione quindi 18è scritto come XVIII non IIXX (10 + 10 - 1 - 1)
    • Non sottrarre un numero da uno che è più di dieci volte maggiore.
      È possibile sottrarre 1da 5 o 10 , ma non è da50, 100, 500...

Esempio

Input:

Aa  
BAa  
CCCXLVII   
MMMCDVII  
ABADDF  
XVVX  
FAASGSH  
DXCCDA  
AaBbcDEf   

Output:

4 {a=5, A=1}  
14 {B=10, a=5, A=1}  
347 {C=100, L=50, X=10, V=5, I=1}  
347 {M=100, D=50, C=10, V=5, I=1}  
1921 {A=1000, B=100, D=10, F=1}  
'XVVX' failed Roman numeral test  
7191 {F=5000, A=1000, S=100, G=10, H=1}  
'DXCCDA' failed Roman numeral test
4444 {a=5000, A=1000, b=500, B=100, D=50, c=10, f=5, E=1}  

3
@IamOgbz questo si è trasformato in una grande domanda ma ha attirato molte domande nei commenti lungo la strada. Ora che hai abbastanza reputazione, ti consiglio il sandbox . Lo trovo molto utile per ottenere domande proprio prima di pubblicare.
trichoplax,

CCCLXVII non sarebbe interpretato come CCCXLVII, dando 347?
Skyler,

@Skyler hai perfettamente ragione, aggiornerò ora! Grazie.
iamogbz,

Non vedo alcuna restrizione su quali valori possono avere le singole lettere (e in effetti tu citi 20, che non è il valore di un numero romano standard). Intendi dire che qualsiasi numero intero positivo può essere rappresentato da un numero romano? In tal caso, Aaha un valore di 1 (A = 1, a = 2).
msh210,

@ msh210 poiché le lettere possono essere interpretate solo come numeri romani, ne consegue che i valori delle singole lettere possono essere potenze solo di 10 o 5 volte potenze di 10. 20 è stato menzionato solo in relazione alla combinazione di due numeri romani (e per sottolineare che IXX = 19 non è una sottrazione valida). Spero che ti chiarisca.
iamogbz,

Risposte:


1

Python 2, 415 444 440 419 416 byte

Dopotutto, non ci sono molti numeri romani. Questo script li crea tutti e controlla tutte le permutazioni dell'input, quindi restituisce la corrispondenza più piccola.

a=raw_input()
g=range
b=list(set(a))+[' ']*9
from itertools import*
c=[]
s={}
u=1000
for i in g(10*u):
 t,f=(10*u,9*u,5*u,4*u,u,900,500,400,100,90,50,40,10,9,5,4,1),i;r=""
 for j in g(17):k=i/t[j];r+=('W MW Q MQ M CM D CD C XC L XL X IX V IV I').split()[j]*k;i-=t[j]*k
 s[r]=f
for i in permutations(b[:9]):
 r=''
 for j in a:r+='IVXLCMQWE'[i.index(j)]
 if r in s:c+=[s[r]]
print c and min(c)or'%s failed Roman numeral test'%a

Questa è una buona risposta alla sfida come è ora. Ma nella conversazione di commento che è stata cancellata presto, è stato suggerito che questo sistema (non reale) continua dopo M = 1000, con simboli per 5k, 10k e così via. Guarda il primo esempio in alto: {A = 10, I = 1, X = 5, ... Z = 1000000} è deciso dalla tua interpretazione
edc65

.., e l'ultimo esempio, a = 5000 ...
edc65,

L'ho aggiornato per gestire tutti i casi di test indicati. Dubito che questo approccio possa essere esteso oltre 10.000 in quanto richiede O (n!) Tempo sul numero di cifre romane.
Skyler,

@Skyler i casi di test non sono esaustivi. Il programma dovrebbe gestire tutte le possibili permutazioni degli input validi che possono essere interpretati secondo le regole numerali romane, con preferenza data ai numeri più bassi in casi ambigui. Inoltre, il tuo codice non è in grado di gestire l'ultimo link del
iamogbz,

Non è import itertools as iquindi i.permutationspiù breve?
gatto
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.