Conversion de chiffres romains chiffrés en décimales arabes

16

Écrivez un algorithme pour interpréter une séquence de lettres comme un chiffre romain. (voir les règles des chiffres romains ci-dessous)

Chaque lettre distincte a une valeur décimale arabe correspondante, pas de maximum. Mais vous n'avez pas la clé à l'avance, c'est donc {A=10, I=1, X=5, ... Z=1000000}votre interprétation qui en décide.

Défi

  1. Lire l'entrée via STDINou équivalent et écrire la sortie via STDOUTou équivalent
  2. Les entrées valides sont des combinaisons de lettres majuscules et minuscules, c'est-à-dire une correspondance \[a-zA-Z]+\
  3. L'entrée doit être validée pour voir si la séquence de lettres peut être interprétée comme un chiffre romain valide
  4. Si l'entrée réussit la validation, la sortie valide doit être l'interprétation décimale arabe la plus basse et la clé utilisée, c'est Aa-à- dire est interprétée comme 4 {a=5, A=1} non 6 {A=5, a=1} ou 9 {a=10, a=1}

Règles du chiffre romain

  1. Seules les lettres représentant des puissances de dix peuvent être répétées, au maximum trois fois successivement et quatre fois au total par exemple II III XXXIX

  2. Si une ou plusieurs lettres sont placées après une autre lettre de valeur supérieure, ajoutez ce montant

    AAaa   => 22 {A=10, a=1}          (20 + 2 = 22)  
    bbAAaa => 222 {b=100, A=10, a=1}  (200 + 20 + 2 = 222)   
    
  3. Si une lettre est placée avant une autre lettre de valeur supérieure, soustrayez ce montant

    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)  
    

    Plusieurs règles s'appliquent pour soustraire les montants des chiffres romains:

    • Seuls les pouvoirs Soustraire de dix -à- dire 1, 10, 100... non 5, 50, 500...
    • Aucune double soustraction 18n'est donc écrite comme XVIII non IIXX (10 + 10 - 1 - 1)
    • Ne soustrayez pas un nombre de celui qui est plus de dix fois supérieur.
      Vous pouvez soustraire 1de 5 ou 10 , mais pas de50, 100, 500...

Exemple

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}  
iamogbz
la source
3
@IamOgbz, cela s'est transformé en une grande question mais a attiré beaucoup de questions dans les commentaires en cours de route. Maintenant que vous avez assez de réputation, je recommande le bac à sable . Je trouve cela très utile pour obtenir des questions juste avant de poster.
trichoplax
CCCLXVII ne serait-il pas interprété comme CCCXLVII, donnant 347?
Skyler
@Skyler vous avez absolument raison, mettra à jour maintenant! Merci.
iamogbz
Je ne vois aucune restriction sur les valeurs que les lettres individuelles peuvent avoir (et en effet vous mentionnez 20, ce qui n'est pas la valeur d'un chiffre romain standard). Voulez-vous dire que tout entier positif peut être représenté par un chiffre romain? Dans ce cas, Aaa une valeur de 1 (A = 1, a = 2).
msh210
@ msh210 car les lettres ne peuvent être interprétées que comme des chiffres romains, il s'ensuit que les valeurs individuelles des lettres ne peuvent être que des puissances de 10 ou 5 fois des puissances de 10. 20 n'a été mentionnée que pour la combinaison de deux chiffres romains (et pour souligner que IXX = 19 n'est pas une soustraction valide). J'espère que cela vous éclaircira.
iamogbz

Réponses:

1

Python 2, 415 444 440 419 416 octets

Après tout, il n'y a pas beaucoup de chiffres romains. Ce script les crée tous et vérifie toutes les permutations de l'entrée, puis renvoie la plus petite correspondance.

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
Skyler
la source
C'est une bonne réponse au défi tel qu'il est actuellement. Mais dans la conversation de commentaires qui a été effacée au début, il a été laissé entendre que ce système (non réel) continue après M = 1000, avec des symboles pour 5k, 10k et ainsi de suite. Regardez le premier exemple en haut: {A = 10, I = 1, X = 5, ... Z = 1000000} est décidé par votre interprétation
edc65
.., et le dernier exemple, a = 5000 ...
edc65
Je l'ai mis à jour pour gérer tous les cas de test donnés. Je doute que cette approche puisse être étendue au-delà de 10 000 car cela prend du temps O (n!) Sur le nombre de chiffres romains.
Skyler
@Skyler les cas de test ne sont pas exhaustifs. Le programme doit gérer toutes les permutations possibles des entrées valides qui peuvent être interprétées selon les règles des chiffres romains, avec une préférence donnée aux nombres inférieurs dans les cas ambigus. De plus, votre code n'a pas pu gérer le dernier lien du
iamogbz
N'est-ce pas import itertools as iet puis i.permutationsplus court?
chat