Текстовый файл состоит из заглавных букв латинского алфавита - цифр римской системы счисления I, V, X, L, C, D, M.
Определите в прилагаемом файле максимальное количество идущих подряд символов, которые представляют собой корректную римскую запись десятичного числа.
Если найдено несколько таких последовательностей, выберите ту которая обозначает наименьшее десятичное число.
В ответе укажите десятичное число, соответствующее найденной последовательности римских цифр.
Для выполнения этого задания следует написать программу.
Примечание.
В римской системе счисления приняты следующие правила:
1) в качестве цифр используют заглавные латинские буквы I, V, X, L, C, D, M, числовое значение которых 1, 5, 10, 50, 100, 500 и 1000 соответственно;
2) цифры V, L, D никогда не повторяются;
3) цифры I, X, C, M могут повторяться не более трёх раз подряд;
4) если меньшая цифра стоит слева от большей, её значение вычитается из большей; вычитать можно только одну цифру I, X или C; вычитаемое не может быть меньше одной десятой от уменьшаемого;
5) если цифра стоит справа от большей или равной, их значения складываются;
6) цифры в записи числа располагаются слева направо в порядке невозрастания их числового значения за исключением случаев вычитания.
Например, римская запись MMXXVI корректна обозначает число 2026, а запись MDDIVXXX некорректна.
Решение
Regexp
🔹 Шаг 1. Импортируем finditer и описываем функцию to_dec
from re import finditer
def to_dec(r):
dct = {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000}
d = dct[r[-1]]
📌 Импортируем finditer и описываем функцию to_dec: по римской записи считаем число в десятичной системе.
🔹 Шаг 2. В to_dec идём справа налево: если символ не меньше следующего
for i in range(len(r) - 2, -1, -1):
if dct[r[i]] >= dct[r[i + 1]]:
d += dct[r[i]]
else:
d -= dct[r[i]]
return d
📌 В to_dec идём справа налево: если символ не меньше следующего — прибавляем, иначе вычитаем.
🔹 Шаг 3. Читаем файл, задаём регулярное выражение для корректной римской записи…
s = open("24_yV2363k.txt").read()
reg = r"M{,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})"
matches = [(len(m.group()), m.group()) for m in finditer(reg, s) if m.group()]
📌 Читаем файл, задаём регулярное выражение для корректной римской записи и собираем все совпадения с их длинами.
🔹 Шаг 4. Сортируем список: сначала по убыванию длины, при равной длине
matches.sort(key=lambda x: (-x[0], to_dec(x[1])))
📌 Сортируем список: сначала по убыванию длины, при равной длине — по возрастанию десятичного значения.
🔹 Шаг 5. Жми RUN
print(to_dec(matches[0][1]))
📌 Жми RUN — в выводе будет 2388 (самая длинная запись; при равенстве длин — наименьшее число).
✅ Ответ: 2388
🔹 Полный код
from re import finditer
def to_dec(r):
dct = {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000}
d = dct[r[-1]]
for i in range(len(r) - 2, -1, -1):
if dct[r[i]] >= dct[r[i + 1]]:
d += dct[r[i]]
else:
d -= dct[r[i]]
return d
s = open("24_yV2363k.txt").read()
reg = r"M{,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})"
matches = [(len(m.group()), m.group()) for m in finditer(reg, s) if m.group()]
matches.sort(key=lambda x: (-x[0], to_dec(x[1])))
print(to_dec(matches[0][1]))