Порахуйте від 1 до 100… в римських цифрах


29

Напишіть програму, яка налічує від 1 до 100, у « Римських цифрах» та надрукуйте ці цифри за стандартним висновком. Кожне з чисел повинно бути розділене пробілами.

Ви не можете використовувати будь-яку вбудовану функцію для перетворення на римські цифри, а також зовнішнє додаток чи бібліотеку для цього.

Бажаний результат

I II III IV V VI VII VIII IX X XI XII XIII XIV XV XVI XVII XVIII XIX XX XXI XXII XXIII XXIV XXV XXVI XXVII XXVIII XXIX XXX XXXI XXXII XXXIII XXXIV XXXV XXXVI XXXVII XXXVIII XXXIX XL XLI XLII XLIII XLIV XLV XLVI XLVII XLVIII XLIX L LI LII LIII LIV LV LVI LVII LVIII LIX LX LXI LXII LXIII LXIV LXV LXVI LXVII LXVIII LXIX LXX LXXI LXXII LXXIII LXXIV LXXV LXXVI LXXVII LXXVIII LXXIX LXXX LXXXI LXXXII LXXXIII LXXXIV LXXXV LXXXVI LXXXVII LXXXVIII LXXXIX XC XCI XCII XCIII XCIV XCV XCVI XCVII XCVIII XCIX C

Оскільки це кодове завдання для гольфу, виграє найкоротший код .


4
39 відсутній X.
Тор

@Thor Виправлено, дякую;)
Averroes

1
Я дуже хочу використовувати INTERCAL для цього.
Вейджун Чжоу

чи можна її розділити новими рядками? А що робити з проміжними / провідними просторами / новинками?
FantaC

Відповіді:


68

Perl 69 байт

s;.;y/XVI60-9/CLXVIX/dfor$a[$_].="32e$&"%72726;gefor 1..100;print"@a"

Працює за допомогою магічної формули. Вираз "32e$&"%72726перетворює кожну цифру таким чином:
0⇒32, 1⇒320, 2⇒3200, 3⇒32000, 4⇒29096, 5⇒56, 6⇒560, 7⇒5600, 8⇒56000, 9⇒50918

Після застосування перекладу y/016/IXV/ми маємо це: 0 :
32, 1⇒32 I , 2⇒32 II , 3⇒32 III , 4⇒29 I 9 V , 5⇒5 V , 6⇒5 VI , 7⇒5 VII , 8⇒5 VIII , 9⇒5 I 9 X 8

Решта цифр ( 2-57-9) видаляються. Зауважте, що це можна покращити на один байт, використовуючи формулу, яка перекладається 012замість 016, спрощуючи /XVI60-9/до /XVI0-9/. Я не зміг його знайти, але, можливо, вам пощастить більше.

Після того, як одна цифра була перетворена таким чином, процес повторюється для наступної цифри, додаючи результат і перекладаючи попередній XVIs, щоб CLXодночасно відбувся переклад нової цифри.

Оновлення
Вичерпний пошук не виявив нічого коротшого. Однак я знайшов альтернативне 69-байтне рішення:

s;.;y/XVI0-9/CLXIXV/dfor$a[$_].="57e$&"%474976;gefor 1..100;print"@a"

Цей використовується для 0-2заміни IXV, але має модуль, який на одну цифру довший.


Оновлення: 66 65 байт

Ця версія помітно відрізняється, тому я, мабуть, повинен сказати про неї кілька слів. Формула, яку він використовує, насправді на один байт довше!

Не в змозі скоротити формулу більше, ніж є, я вирішив пограти в те, що мав. Не минуло часу, поки я згадав свого старого друга $\. Коли printвипуск видається, $\автоматично додається до кінця виводу. Мені вдалося позбутися незручної $a[$_]конструкції для покращення на два байти:

s;.;y/XVI60-9/CLXVIX/dfor$\.="32e$&"%72726;ge,$\=!print$"for 1..100

Набагато краще, але це $\=!print$"все-таки виглядало дещо багатослівним. Потім я згадав альтернативну формулу, рівну довжині, яку я знайшов, яка не містила числа 3в жодному з її цифрових перетворень. Отже, слід мати можливість використовувати $\=2+printзамість цього і підміняти 3пробіл:

s;.;y/XVI0-9/CLXIIX V/dfor$\.="8e$&"%61535;ge,$\=2+print for 1..100

Також 67 байт, через необхідний пробіл між printі for.

Редагувати : це можна покращити на один байт, перемістивши printвперед:

$\=2+print!s;.;y/XVI0-9/CLXIIX V/dfor$\.="8e$&"%61535;gefor 1..100

Оскільки заміщення потрібно повністю оцінити до початку print, присвоєння $\все одно відбуватиметься останнім. Видалення пробілу між ними geта forвидасть попередження про депресію, але в іншому випадку дійсне.

Але, якщо існувала формула, яка ніде не використовувалась 1, $\=2+printстає $\=printще на два байти економією. Навіть якби він був на один байт довше, це все одно було б покращенням.

Як виявляється, така формула існує, але вона на один байт довше оригіналу, в результаті виходить остаточна оцінка в 65 байт :

$\=print!s;.;y/XVI60-9/CLXXI V/dfor$\.="37e$&"%97366;gefor 1..100

Методика

Було задано питання, як можна піти про пошук такої формули. Взагалі, знайти магічну формулу для узагальнення будь-якого набору даних - це питання ймовірного. Тобто ви хочете вибрати форму, яка максимально вірогідна, щоб отримати щось подібне до бажаного результату.

Вивчаючи перші кілька римських цифр:

0:
1: I
2: II
3: III
4: IV
5: V
6: VI
7: VII
8: VIII
9: IX

є певна закономірність. Зокрема, від 0-3, а потім знову від 5-8 , кожен наступний доданок збільшується в довжину на одну цифру. Якби ми хотіли створити відображення від цифр до цифр, ми хотіли б мати вираз, який також збільшується в довжину на одну цифру за кожен наступний член. Логічний вибір - k • 10 d, де d - відповідна цифра, а k - будь-яка ціла константа.

Це працює для 0-3 , але 4 потрібно розбити шаблон. Що ми можемо зробити тут, це дотримуватися модуля:
k • 10 d % m , де m десь між k • 10 3 та k • 10 4 . Це дозволить залишити діапазон 0-3 недоторканим і змінити 4 таким чином, щоб він не містив чотири Iс. Якщо ми додатково обмежимо наш алгоритм пошуку таким чином, щоб модульний залишок 5 , назвемо його j , був меншим від m / 1000 , це забезпечить також регулярність від 5-8 . Результат виглядає приблизно так:

0: k
1: k0
2: k00
3: k000
4: ????
5: j
6: j0
7: j00
8: j000
9: ????

Як ви можете бачити, якщо ми замінимо 0з I, 0-3 і 5-8 все гарантовано буде відображатися правильно! Значення для 4 і 9, однак, повинні бути вимушеними. Зокрема, 4 повинні містити один 0і один j(у такому порядку), а 9 - один 0, після якого - ще одна цифра, яка більше ніде не з’являється. Звичайно, існує ряд інших формул, які за певним збігом обставин можуть дати бажаний результат. Деякі з них можуть бути навіть коротшими. Але я не думаю, що є такі, які мають таку ймовірність успіху, як ця.

Я також експериментував із кількома замінами для Iта / або Vз деяким успіхом. Але на жаль, нічого коротшого від того, що я вже мав. Ось перелік найкоротших я знайдених рішень (кількість рішень на 1-2 байти важчі, щоб їх перерахувати):

y/XVI60-9/CLXVIX/dfor$\.="32e$&"%72726
y/XVI0-9/CLXIXV/dfor$\.="57e$&"%474976
y/XVI0-9/CLXIVXI/dfor$\.="49e$&"%87971

y/XVI0-9/CLXIIXIV/dfor$\.="7e$&"%10606  #
y/XVI0-9/CLXIIXIV/dfor$\.="7e$&"%15909  # These are all essentially the same
y/XVI0-9/CLXIIXIV/dfor$\.="7e$&"%31818  #

y/XVI0-9/CLXIIX V/dfor$\.="8e$&"%61535  # Doesn't contain 3 anywhere

y/XVI60-9/CLXXI V/dfor$\.="37e$&"%97366 # Doesn't contain 1 anywhere

3
Як ти знайшов чарівну формулу?
Рубен Верборг

1
@RubenVerborgh Незабаром оновлю своє повідомлення з додатковою інформацією щодо методології.
примо

15

HTML + JavaScript + CSS (137)

HTML (9)

<ol></ol>

JavaScript (101)

for(i=1;i<=100;i++){document.getElementsByTagName('ol')[0].appendChild(document.createElement('li'))}

CSS (27)

ol{list-style:upper-roman​}

Вихід

Пронумерований список з римськими цифрами

...

Демо на JSBin


1
81 байт-версія лише для JS: document.write('<ol>'+"<li style='list-style:upper-roman'/>".repeat(100)+'</ol>')(ES6)
Paperjam

або 66 у Chromedocument.write("<li style='list-style:upper-roman'/>".repeat(100))
Slai

10

Пітон 116

кращий гольф-код відповіді скаувера:

r=lambda a,b,c:('',a,2*a,3*a,a+b,b,b+a,b+a+a,b+3*a,a+c);print' '.join(i+j for i in r(*'XLC')for j in r(*'IVX'))+' C'

8

Пітона, 139

print' '.join(' '.join(i+j for  j in ' _I_II_III_IV_V_VI_VII_VIII_IX'.split('_'))for i in ' _X_XX_XXX_XL_L_LX_LXX_LXXX_XC'.split('_'))+' C'

6

C, 177 160 147 символів

Є більш короткі рішення, але жодне в С, тому ось моя спроба.

Нове рішення, абсолютно відмінне від мого попереднього:

char*c;
f(n){
    printf("%.*s",n%5>3?2:n%5+n/5,c+=n%5>3?n%4*4:2-n/5);
}
main(i){
        for(;i<100;putchar(32))
                c="XLXXXC",f(i/10),
                c="IVIIIX",f(i++%10);
        puts("C");
}

Попереднє рішення (160 символів):

Логіка:
1. fдрукує число від 1 до 10. c- це використовувані цифри, які можуть бути IVXабо XLC. Називається один раз на десятки один раз за тими.
2. Якщо n%5==0- нічого не друкуйте, або c[n/5]є, Iабо V( Lабо C).
3. Якщо n%4==4- 4або 9- друк I(або X), автор n+1.
4. Якщо n>4- друк 5(тобто Vабо L), то n-5.
5. Якщо n<4- друк, Iто n-1(тобто nрази I).

char*c;
p(c){putchar(c);}
f(n){
        n%5?
                n%5>3?
                        f(1),f(n+1):
                        n>4?
                                f(5),f(n-5):
                                f(n-1,p(*c)):
                n&&p(c[n/5]);
}
main(i){
        for(;++i<101;p(32))
                c="XLC",f(i/10),
                c="IVX",f(i%10);
        p(10);
}

137:f(c,n){printf("%.*s",n%5>3?2:n%5+n/5,"XLXXXCIVIIIX "+c+(n%5>3?n%4*4:2-n/5));}main(i){for(;i<100;f(12,4))f(0,i/10),f(6,i++%10);puts("C");}
гастропнер

5

JavaScript, 123

Натхненний довшою версією, я натрапив на польську групу новин (принаймні, Chrome вважав, що це польська мова).

for(i=100,a=[];n=i--;a[i]=r)
  for(r=y='',x=5;n;y++,x^=7)
    for(m=n%x,n=n/x^0;m--;)
      r='IVXLC'[m>2?y+n-(n&=-2)+(m=1):+y]+r;
alert(a)

5

Q ( 81 80)

2-й зріз:

1_,/'[($)``X`XX`XXX`XL`L`LX`LXX`LXXX`XC cross``I`II`III`IV`V`VI`VII`VIII`IX],"C"

1-й зріз:

1_,/'[$:[``X`XX`XXX`XL`L`LX`LXX`LXXX`XC cross``I`II`III`IV`V`VI`VII`VIII`IX]],"C"

4

Пітона, 168

r=lambda n,l,v:(r(n,l[1:],v[1:])if n<v[0]else l[0]+r(n-v[0],l,v))if n else''
for i in range(1,101):print r(i,'C XC L XL X IX V IV I'.split(),[100,90,50,40,10,9,5,4,1]),

Пояснення

Використовуючи ці значення, візьміть найбільше значення не більше n і відніміть його від n. Повторюйте, поки n не дорівнює 0.

'C'  = 100
'XC' = 90
'L'  = 50
'XL' = 40
'X'  = 10
'IX' = 9
'V'  = 5
'IV' = 4
'I'  = 1

1
r=lambda n,l,v:n and(n<v[0]and r(n,l[1:],v[1:])or l[0]+r(n-v[0],l,v))or""зберігає два символи. Інакше дуже приємно.
cemper93

4

Рубін 1,9, 140 132

r=" "
100.times{r+=?I
0while[[?I*4,"IV"],["VIV","IX"],[?X*4,"XL"],["LXL","XC"],[/(.)((?!\1)[^I])\1/,'\2']].any?{|q|r.sub! *q}
$><<r}

Це буквально налічує від 1 до 100 в римських цифрах. Починається з порожнього рядка, потім проходить цикл через додавання "Я", а потім повторно застосовує ряд правил заміни, ефективно додаючи 1.

Редагувати: Додано номер версії, оскільки ?Iпрацює лише в 1.9, і використовував зміни @ Говарда для обрізки деяких символів.


Ви можете зберегти два знаки: r while-> 0while, r.sub!(*q)-> r.sub! *q. Ви також можете перетягнути друк всередині циклу та використовувати 100.times{...}замість оператора map.
Говард

(%w[IIII VIV XXXX LXL]<</(.)((?!\1)[^I])\1/).zip(%w(IV IX XL XC)<<'\2')економить 7 символів.
steenslag

4

Рубін 112 знаків

101.times{|n|r=' ';[100,90,50,40,10,9,5,4,1].zip(%w(C XC L XL X IX V IV I)){|(k,v)|a,n=n.divmod k;r<<v*a};$><<r}

В основному з використанням to_romanметоду, поясненого тут , але з використанням короткого масиву для стислості.


4

Mathematica 159 150 142

c = {100, 90, 50, 40, 10, 9, 5, 4, 1};
Table["" <> Flatten[ConstantArray @@@ Thread@{StringSplit@"C XC L XL X IX V IV I", 
  FoldList[Mod, k, Most@c]~Quotient~c}], {k, 100}]

римські цифри


Вбудований розчин :, IntegerString38 символів

IntegerString[k, "Roman"]~Table~{k, 100}

2

perl 205

@r = split //, "IVXLC";
@n = (1, 5, 10, 50, 100);

for $num (1..100) {
  for($i=@r-1; $i>=0; $i--) {
    $d = int($num / $n[$i]);
    next if not $d;
    $_ .= $r[$i] x $d;
    $num -= $d * $n[$i];
  }
  $_ .= " ";
}
s/LXXXX/XC/g;
s/XXXX/XL/g;
s/VIIII/IX/g;
s/IIII/IV/g;
print;

Гольф:

@r=split//,"IVXLC";@n=(1,5,10,50,100);for$num(1..100){for($i=@r-1;$i>=0;$i--){$d=int($num/$n[$i]);next if!$d;$_.=$r[$i]x$d;$num-=$d*$n[$i];}$_.=" ";}s/LXXXX/XC/g;s/XXXX/XL/g;s/VIIII/IX/g;s/IIII/IV/g;print;

2

СУМКА 184

S V(100)="C",V(90)="XC",V(50)="L",V(40)="XL",V(10)="X",V(9)="IX",V(5)="V",V(4)="IV",V(1)="I" F I=1:1:100 S S=I,N="" F  Q:'S  S N=$O(V(N),-1) I S&(S'<N ) S S=S-N W V(N) S N="" w:'S " "

Той самий алгоритм, що і @cardboard_box, від якого я взяв пояснення дослівно -

Пояснення

Використовуючи ці значення, візьміть найбільше значення не більше n і відніміть його від n. Повторюйте, поки n не дорівнює 0.

'C'  = 100
'XC' = 90
'L'  = 50
'XL' = 40
'X'  = 10
'IX' = 9
'V'  = 5
'IV' = 4
'I'  = 1

2

R , 85 байт

R=.romans
for(r in 1:100){while(r>0){cat(names(R[I<-R<=r][1]))
r=r-R[I][1]}
cat(" ")}

Спробуйте в Інтернеті!

Використовує випадкову utilsзмінну пакета .romansдля отримання значень римських цифр, але робить перетворення само собою; вбудований підхід складе 20 байт:cat(as.roman(1:100))


Дивно, але вбудований підхід, про який ви згадуєте, не спрацьовує так, як це ... треба вводити cat(paste(as.roman(1:100)))або просто as.roman(1:100). Дивно.
JayCe

@JayCe непарне; Я, мабуть, не перевіряв це ... Документи catсвідчать про те, що він здійснює менше перетворення, ніж printі працює лише на atomicвекторах - так що це пояснює!
Джузеппе

1

APL 128

Я спробував рішення щодо індексації в APL:

r←⍬                                                                             
i←1                                                      
l:r←r,' ',('   CXI LV CX'[,⍉((1+(4 4 2 2⊤0 16 20 22 24 32 36 38 39 28)[;1+(3⍴10)⊤i])×3)-4 3⍴2 1 0])~' '
→(100≥i←i+1)/l                                                                  
r              

Він може бути на 4 байти коротшим за початковим показником 0 замість 1, але справжній пробіл - це генерування матриці індексу через:

4 4 2 2⊤0 16 20 22 24 32 36 38 39 28

Поки що мені не вдалося генерувати показники на льоту!


1

LaTeX (138)

\documentclass{minimal}
\usepackage{forloop}
\begin{document}
\newcounter{i}
\forloop{i}{1}{\value{i} < 101}{\roman{i}\par}
\end{document}

1
-1: у запитанні сказано: "Ви не можете використовувати будь-яку вбудовану функцію для перетворення на римські цифри"
izabera



1

VBA (Excel), 245 байт

створена функція для повторення та заміни - 91 байт

Function s(a,b):s=String(a,b):End Function Function b(x,y,z):b=Replace(x,y,z):End Function

використовуючи негайне вікно ( 154 байти )

p="I":for x=1to 100:?b(b(b(b(b(b(b(b(s(x,p),s(100,p),"C"),s(90,p),"XC"),s(50,p),"L"),s(40,p),"XL"),s(10,p),"X"),s(9,p),"IX"),s(5,p),"V"),s(4,p),"IV"):next


0

Java (OpenJDK 8) , 152 байти

a->{String[] t=",X,XX,XXX,XL,L,LX,LXX,LXXX,XC,,I,II,III,IV,V,VI,VII,VIII,IX".split(",");for(int i=1;i<100;i++){a+=t[i/10]+t[i%10+10]+" ";}return a+"C";}

Спробуйте в Інтернеті!

Пояснення:

String[] t=",X,XX,XXX,XL,L,LX,LXX,LXXX,XC,,I,II,III,IV,V,VI,VII,VIII,IX".split(",");
//Create an array of numerals, first half represents tens place, second half represents ones place
    for(int i=1;i<100;i++){             
//Loop 99 times
        a+=t[i/10]+t[i%10+10]+" ";   
//Add tens place and ones place to the string
    }return a+"C";                         
//Add numeral for 100 and return the string

0

TeX, 354 байти

\let~\let~\d\def~\a\advance~\b\divide~\x\expandafter~\f\ifnum{~~\newcount~\n~\i~\j~\k~\u~\v}~~\or\d\p#1{\ifcase#1C~2~L~5~X~2~V~5~I\fi}\d\q#1{\p{#1~}}\d\r{\j0
\v100\d\m{\d\w{\f\n<\v\else\p\j\a\n-\v\x\w\fi}\w\f\n>0\k\j\u\v\d\g{\a\k2\b\u\q\k}\g\f\q\k=2\g\fi\a\n\u\f\n<\v\a\n-\u\a\j2\b\v\q\j\else\p\k\fi\x\m\fi}\m}\i1\d\c{
\f\i<101 \n\i\r\a\i1 \x\c\fi}\c\bye

Деякі пояснення: TeX надає вбудовану команду \romannumeralдля перетворення чисел у римські цифри. Оскільки питання не дозволяє використовувати вбудовані функції, вищевказаний код є гольф-версією того ж алгоритму, який використовує оригінальний компілятор TeX для Knuth для \romannumeral(див. TeX: Програма , § 69, print_roman_int), повторно реалізованої в TeX.

Оскільки він хоче залишити радість дивуватися, як цей код працює для читача, Кнут відмовляється давати пояснення цієї частини коду. Тож я піду за прикладом і просто дам необов’язану та трохи змінену версію, яка ближче до оригіналу, ніж наведений вище код:

\newcount\n
\newcount\j
\newcount\k
\newcount\u
\newcount\v

\def\chrnum#1{\ifcase#1m\or 2\or d\or 5\or c\or 2\or l\or 5\or x\or 2\or v\or 5\or i\fi}
\def\chrnumM#1{\chrnum{#1\or}}

\def\roman#1{%
    \n=#1\relax
    \j=0\relax
    \v=1000\relax
    \def\mainloop{%
        \def\while{%
            \ifnum\n<\v
            \else
                \chrnum\j
                \advance\n -\v
                \expandafter\while
            \fi
        }\while
        \ifnum\n>0\relax
            \k=\j \advance\k 2\relax
            \u=\v \divide\u \chrnumM\k
            \ifnum\chrnumM\k=2\relax
                \advance\k 2\relax
                \divide\u \chrnumM\k
            \fi
            \advance\n \u
            \ifnum\n<\v
                \advance\n -\u
                \advance\j 2\relax
                \divide\v \chrnumM\j
            \else
                \chrnum\k
            \fi
            \expandafter\mainloop
        \fi
    }\mainloop
}

\newcount\i \i=1
\def\countloop{%
    \ifnum\i<100\relax
        \roman\i\ 
        \advance\i 1
        \expandafter\countloop
    \fi
}\countloop
\bye
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.