那些贪婪的罗马人!


30

给定一个严格的正整数,请仅使用加法则返回最短的罗马数字。输出必须MDCLXVI按该顺序包含零个或多个每个字符。14因此,该数字必须为XIIII而不是XIV

字符的数值为M= 1000,D= 500,C= 100,L= 50,X= 10,V= 5,I= 1。

例子

3III

4 → IIII

9VIIII

42XXXXII

796DCCLXXXXVI

2017MMXVII

16807MMMMMMMMMMMMMMMMDCCCVII


1
你是个仁慈的提问,让4 -> IIII9 -> VIIII也,而不是IX
Magic Octopus Urn


@MagicOctopusUrn VIIII是9的唯一允许输出。
Adám17年

@Adám只是指出您可能也想添加它作为示例,因为4和9的规则相同。
Magic Octopus Urn

Answers:


12

纯英文1059个 1025 678 641 451 399字节

通过删除错误陷阱节省了34个字节。然后通过打高尔夫球节省了384个字节。然后,通过将除法运算与附加运算(“ z”)合并为新运算(“ p”),节省了190个字节。然后通过打高尔夫球节省了52个字节。

A s is a string.
To p a r remainder a s a x string a n number:
If the x is "", exit.
Divide the r by the n giving a q quotient and the r.
Fill a t s with the x's first's target given the q.
Append the t to the s.
To convert a r number to a s:
p the r the s "M" 1000.
p the r the s "D" 500.
p the r the s "C" 100.
p the r the s "L" 50.
p the r the s "X" 10.
p the r the s "V" 5.
p the r the s "I" 1.

这是最终代码的原始版本,外加一个负数错误陷阱:

A roman numeral is a string.

To process a remainder given a roman numeral and a letter string is a number:
  If the letter is "", exit.
  Divide the remainder by the number giving a quotient and the remainder.
  Fill a temp string with the letter's first's target given the quotient.
  Append the temp string to the roman numeral.

To convert a number to a roman numeral:
  If the number is negative, exit.
  Put the number in a remainder.
  Process the remainder given the roman numeral and "M" is 1000.
  Process the remainder given the roman numeral and "D" is  500.
  Process the remainder given the roman numeral and "C" is  100.
  Process the remainder given the roman numeral and "L" is   50.
  Process the remainder given the roman numeral and "X" is   10.
  Process the remainder given the roman numeral and "V" is    5.
  Process the remainder given the roman numeral and "I" is    1.

10
等等,这是一种编程语言吗?
亚当

3
@亚当-是的。普通的英语可以编译,运行以及所有内容。源代码和IDE可以在github.com/Folds/english上找到
Jasper

1
不过要打高尔夫-毕竟,这是代码高尔夫,而不是语言展示。
Sanchises

2
因此,如果您不想将工作外包给我,这就是您使用的语言吗?
corsiKa

@corsiKa-哈哈!只有当我们足够的人开始使用它(并添加到其库中)时,它才能达到临界质量。
贾斯珀(Jasper)

5

APL(Dyalog)25 22字节

'MDCLXVI'/⍨(0,62 5)∘⊤

在线尝试!


很好,基本上是我想到的解决方案。但是,您可以使用复制(/)而不是整形(),以便可以剪切出each和catenate-reduction(¨,/)。
亚当

另外,您可以转换为tradfn主体并输入(),然后使用通勤()删除括号并撰写()。
亚当

谢谢,但是您第二次评论是什么意思?我想不出一种不增加字节数的方法
TwiNight


1
这将是一个片段,除非你算上{}∇f∇周围的功能
TwiNight


5

Python 2,64个字节

f=lambda n,d=5,r='IVXLCD':r and f(n/d,7-d,r[1:])+n%d*r[0]or'M'*n

在线尝试!

与其贪婪地占据最大的部分来创建输出字符串,不如从头开始创建它。例如,的数量In%5,然后的数量Vn/5%2,依此类推。这是混合碱转化,连续比率为5和2交替。

这是一个迭代等效项:

Python 2,68个字节

n=input();s='';d=5
for c in'IVXLCD':s=n%d*c+s;n/=d;d^=7
print'M'*n+s

在线尝试!

M的需要单独处理,因为它们当中任意数量的可能存在,因为没有更大的数字。因此,在分配了其他位置值之后,剩余的值将转换为M

为了比较,一个贪婪的策略(69字节):

Python 2,69个字节

f=lambda n,d=1000,r='MDCLXVI':r and n/d*r[0]+f(n%d,d/(d%3*3-1),r[1:])

在线尝试!

当前数字值d被2或5除以产生下一个数字。d%3告诉我们哪一个值:如果d%3==1,除以2;如果是d%3==2,则除以5。


4

Mathematica,81个字节

Table@@@Thread@{r=Characters@"MDCLXVI",#~NumberDecompose~FromRomanNumeral@r}<>""&

明确使用这些值并推导相应的数字似乎要长一个字节:

Table@@@Thread@{RomanNumeral[n={1000,500,100,50,10,5,1}],#~NumberDecompose~n}<>""&

1
尼斯!:FromRomanNumeral@r
DavidC

4

Excel中,236个 193 161字节

@ BradC节省了43个字节

此时,答案实际上完全属于@ BradC。另外保存了32个字节。

=REPT("M",A1/1E3)&REPT("D",MOD(A1,1E3)/500)&REPT("C",MOD(A1,500)/100)&REPT("L",MOD(A1,100)/50)&REPT("X",MOD(A1,50)/10)&REPT("V",MOD(A1,10)/5)&REPT("I",MOD(A1,5))

格式:

=REPT("M",A1/1E3)
    &REPT("D",MOD(A1,1E3)/500)
    &REPT("C",MOD(A1,500)/100)
    &REPT("L",MOD(A1,100)/50)
    &REPT("X",MOD(A1,50)/10)
    &REPT("V",MOD(A1,10)/5)
    &REPT("I",MOD(A1,5))

您可以通过更换节省一些CONCATENATE&各元素之间,并QUOTIENTINT(A/B)
BradC

再节省2个:如果不是整数,结果REPT已经将其截断了,因此您可以通过删除每个再节省30个字节INT()。保存2个通过更换两个10001E3(尽管Excel似乎并不想继续保持这种方式,一旦你按下回车键)。
BradC

是的,看到了这种1E3行为。答案已更新。
维尔尼施(Wernisch)'17

3

Perl 5,66个字节

65个字节的代码+ -p标志。

$s=1e3;for$@(MDCLXVI=~/./g){$\.=$@x($_/$s);$_%=$s;$s/=--$|?2:5}}{

在线尝试!

在不更改字节数的情况下,MDCLXVI=~/./g可以用M,D,C,L,X,V,I; 代替。和--$|?2:5通过$|--*3+2

更长(99个字节),有:

$_=M x($_/1e3).D x($_%1e3/500).C x($_%500/100).L x($_%100/50).X x($_%50/10).V x($_%10/5).I x($_%5)

3

CJam35 28字节

-7字节感谢Martin Ender

q~{5md\2md\}3*]W%"MDCLXVI".*

在线尝试!

说明

q~         e# Read and eval input (push the input as an integer).
{          e# Open a block:
 5md\      e#  Divmod the top value by 5, and bring the quotient to the top.
 2md\      e#  Divmod that by 2, and bring the quotient to the top.
}3*        e# Run this block 3 times.
]W%        e# Wrap the stack in an array and reverse it. Now we've performed the mixed-base
           e# conversion.
"MDCLXVI"  e# Push this string.
.*         e# Element-wise repetition of each character by the numbers in the other array.
           e# Implicitly join and print.

3

C#,127个字节

f=n=>n>999?"M"+f(n-1000):n>499?"D"+f(n-500):n>99?"C"+f(n-100):n>49?"L"+f(n-50):n>9?"X"+f(n-10):n>4?"V"+f(n-5):n>0?"I"+f(n-1):""

使用递归的纯硬编码三元语句。

完整/格式化版本:

using System;

class P
{
    static void Main()
    {
        Func<int, string> f = null;
        f = n => n > 999 ? "M" + f(n - 1000)
                         : n > 499 ? "D" + f(n - 500)
                                   : n > 99 ? "C" + f(n - 100)
                                            : n > 49 ? "L" + f(n - 50)
                                                     : n > 9 ? "X" + f(n - 10)
                                                             : n > 4 ? "V" + f(n - 5)
                                                                     : n > 0 ? "I" + f(n - 1)
                                                                             : "";

        Console.WriteLine(f(3));
        Console.WriteLine(f(4));
        Console.WriteLine(f(42));
        Console.WriteLine(f(796));
        Console.WriteLine(f(2017));
        Console.WriteLine(f(16807));

        Console.ReadLine();
    }
}

n>0就是n
CalculatorFeline

@CalculatorFeline不在C#中,int不能隐式转换为bool
TheLethalCoder

那真不幸。
CalculatorFeline

@CalculatorFeline是的,有时候C#的类型太强了。
TheLethalCoder

3

05AB1E29 26 25字节

¸5n3×Rvćy‰ì}"MDCLXVI"Ss×J

在线尝试!

说明

¸                           # wrap input in a list
 5n                         # push 5**2
   3×                       # repeat it 3 times
     Rv                     # for each digit y in its reverse
       ć                    # extract the head of the list 
                            # (div result of the previous iteration, initially input)
        y‰                  # divmod with y
          ì                 # prepend to the list
           }                # end loop
            "MDCLXVI"S      # push a list of roman numerals
                      s×    # repeat each a number of times corresponding to the result
                            # of the modulus operations
                        J   # join to string

3

JavaScript(ES6),81 75 69字节

由于@Neil移植了@JörgHülsermann的答案,因此节省了6个字节

@Shaggy节省了6个字节

n=>'MDCLXVI'.replace(/./g,(c,i)=>c.repeat(n/a,n%=a,a/=i%2?5:‌​2),a=1e3)

测试用例:


1
您应该能够n%=xrepeat方法内移动以节省一些字节。
毛茸茸的

1
仅供参考,PHP答案的端口只有69个字节:n=>'MDCLXVI'.replace(/./g,(c,i)=>c.repeat(n/a,n%=a,a/=i%2?5:2),a=1e3)
尼尔(Neil)

感谢@Neil,我更新了帖子。删除了我想重新访问的硬编码数组
Craig Ayre

2

///,50个字节

/1/I//IIIII/V//VV/X//XXXXX/L//LL/C//CCCCC/D//DD/M/

在线尝试!

以一元形式接受输入,我(ab)使用TIO上的页脚字段进行输入,因此输出前带有换行符。


2

Python 3中100 97 96 94 93 91 90个字节

  • 保存4 + 2字节:使用def;数组作为默认参数减少了缩进空间;删除了不需要的变量声明
  • @shooqie保存了1个字节的a%=速记
  • 保存了2个字节:重新排列并(a//i)删除了大括号
  • @Wondercricket保存了1个字节:将数组从默认参数移到函数内,该函数[]以一个缩进空间为代价将其删除,因此节省了1个字节。
def f(a):
 b=1000,500,100,50,10,5,1
 for i in b:print(end=a//i*'MDCLXVI'[b.index(i)]);a%=i

在线尝试!


1
a%=i短了一个字节:)
shooqie

1
您也可以通过将b变量存储为函数中的内容来保存字节。这消除了括号的必要性–b=1000,500,100,50,10,5,1
Wondercricket

2

Cubix,69 74 80字节

/.UI,..N&..0\0&/52"IVXLCDM"U,r%ws;rr3tu;pw..u;qrUosv!s.u\psq,!@Us(0;U

在线尝试!

        / . U I
        , . . N
        & . . 0
        \ 0 & /
5 2 " I V X L C D M " U , r % w
s ; r r 3 t u ; p w . . u ; q r
U o s v ! s . u \ p s q , ! @ U
s ( 0 ; U . . . . . . . . . . .
        . . . .
        . . . .
        . . . .
        . . . .

观看跑步

我设法将其压缩得更多,但是仍然有些讨厌的操作,尤其是在顶面上。

  • 52"IVXLCDM"U将必要的除数和字符放在堆栈中。5和2将用于减小div / mod值,并且使用后将丢弃这些字符。
  • UIN0/&0\&,/Uu转到顶部,开始漫长的浏览以获取输入并将1000推入堆栈。完成初始划分,然后调头到r下一个代码片段。这是我一直在寻求节省的领域。
  • ,r%ws;rrdivmod循环的开始。整数除法,将结果旋转远离mod,然后重新排列堆栈顶部以减少输入,电流除数和除法结果。
  • 3tus 将当前角色移到顶部,然后将其与除法结果交换。
  • !vsoUs(0;U这是打印循环。当div结果大于0时,与字符输出交换,交换回去,递减,压入0并将其丢弃。设为0时,重定向弹出堆栈(删除除法结果)并绕多维数据集。
  • \u;pwpsq,!@Urq;u经过一些重定向,这会将字符从堆栈中删除,将5和2移到顶部,交换它们并将其推回原位。剩余的用于减少除数。如果减小到0,则停止,否则将5或2推到底部,然后重新进入循环。

1

Mathematica,130个字节

(f=#~NumberDecompose~{1000,500,100,50,10,5,1};""<>{Flatten@Table[Table[{"M","D","C","L","X","V","I"}[[i]],f[[i]]],{i,Length@f}]})&

1

Python 2中109个 90字节

lambda n,r=[1000,500,100,50,10,5,1]:''.join(n%a/b*c for a,b,c in zip([n+1]+r,r,'MDCLXVI'))

在线尝试!


1000可以1e3(如果您不介意这是一个浮动,这应该不成问题)
CalculatorFeline

@CalculatorFeline它将结果转换为float,并且您不能将字符串乘以浮点数:c
Rod Rod


1

T-SQL,164字节

SELECT REPLICATE('M',n/1000)+IIF(n%1000>499,'D','')
      +REPLICATE('C',n%500/100)+IIF(n%100>49,'L','')
      +REPLICATE('X',n%50/10)+IIF(n%10>4,'V','')
      +REPLICATE('I',n%5)
FROM t

添加换行符仅出于可读性。

这个版本更长(230个字符),但是感觉更像“ SQL风格”:

DECLARE @ INT,@r varchar(99)=''SELECT @=n FROM t
SELECT'I's,1v INTO m
INSERT m VALUES('V',5),('X',10),('L',50),('C',100),('D',500),('M',1000)
L:
    SELECT @-=v,@r+=s 
    FROM m WHERE v=(SELECT MAX(v)FROM m WHERE v<=@)
IF @>0GOTO L
SELECT @r

用所有字符值映射表m,然后循环查找最大值<=数字,并连接匹配字符。


1

Japt,34个字节

"IVXLCD"£%(U/=Y=v *3+2Y)îXÃw i'MpU

在线测试!

"IVXLCD"£    %(U/=Y=v  *3+2Y )îXÃ w i'MpU
"IVXLCD"mXY{U%(U/=Y=Yv *3+2,Y)îX} w i'MpU : Ungolfed
                                          : Implicit: U = input number
"IVXLCD"mXY{                    }         : Map each char X and its index Y in this string to:
                  Y=Yv *3+2               :   Set Y to 5 for even indexes, 2 for odd.
               U/=                        :   Divide U by this amount.
            U%(            ,Y)            :   Modulate the old value of U by 5.
                              îX          :   Repeat the character that many times.
                                          : This returns e.g. "IIVCCCD" for 16807.
                                  w       : Reverse the entire string.
                                    i'MpU : Prepend U copies of 'M' (remember U is now the input / 1000).
                                          : Implicit: output result of last expression

1

JavaScript(ES6),65个字节

递归函数。

f=(n,a=(i=0,1e3))=>n?a>n?f(n,a/=i++&1?5:2):'MDCLXVI'[i]+f(n-a):''

怎么样?

第二个递归调用f(n-a)确实应该是f(n-a,a)。通过省略第二个参数,ai在每次将新的罗马数字附加到最终结果时将其重新初始化(分别为1000和0)。这将导致比所需更多的递归,但不会改变函数的结果并节省2个字节。

测试用例


1

J26 23字节

多亏了Adám,节省了3个字节。

'MDCLXVI'#~(_,6$2 5)&#:

在线尝试!

类似于APL的答案基本上是相同的东西。

'MDCLXVI'#~(_,6$2 5)&#:
           (       )&#:   mixed base conversion from decimal
              6$2 5       2 5 2 5 2 5
            _,            infinity 2 5 2 5 2 5
                          this gives us e.g. `0 0 0 0 1 0 4` for input `14`
'MDCLXVI'#~               shape each according to the number of times on the right
                          this is greedy roman numeral base conversion

这并不是说我知道,但强,为什么#.inv不是#:
亚当

@Adám啊,好点。我通常使用#.inv代替#:,因为类似的2 #: 40,而2 #.inv 4实际上是1 0 0
Conor O'Brien

是的,我在APL中也做同样的事情。现在,您的解决方案真正等同于APL解决方案。
亚当

#/; ~; $; &; #:。唯一的区别是,您可以使用无穷大,_而可以0像APL答案那样使用。
亚当

@AdámHuh,很酷。
Conor O'Brien

1

批处理,164字节

@set/pn=
@set s=
@for %%a in (1000.M 500.D 100.C 50.L 10.X 5.V 1.I)do @call:c %%~na %%~xa
@echo %s:.=%
@exit/b
:c
@if %n% geq %1 set s=%s%%2&set/an-=%1&goto c

在STDIN上输入。


1

Oracle SQL,456字节

select listagg((select listagg(l)within group(order by 1)from dual start with trunc((n-nvl(n-mod(n,p),0))/v)>0 connect by level<=trunc((n-nvl(n-mod(n,p),0))/v)))within group(order by v desc)from (select 2849n from dual)cross join(select 1000v,null p,'m'l from dual union select 500,1000,'d'from dual union select 100,500,'c'from dual union select 50,100,'l'from dual union select 10,50,'x'from dual union select 5,10,'v'from dual union select 1,5,'i'from dual)

输出:

mmdcccxxxxviiii

请注意,该行的实际大小为460字节,因为它包括输入数字(2849)。

取消高尔夫:

select listagg(
            (select listagg(l, '') within group(order by 1) 
             from dual 
             start with trunc((n-nvl(p*trunc(n/p),0))/v) > 0 
             connect by level <= trunc((n-nvl(p*trunc(n/p),0))/v) )
        ) within group(order by v desc)
from (select 2348 n
    from dual
) cross join (
    select 1000v, null p, 'm' l from dual union 
    select 500, 1000, 'd' from dual union
    select 100, 500, 'c' from dual union
    select 50, 100, 'l' from dual union
    select 10, 50, 'x' from dual union
    select 5, 10, 'v' from dual union
    select 1, 5, 'i' from dual     
)

它是如何工作的:我计算出每个字母需要多少个字母,方法是计算一个最大的字母(M的无穷大),然后在当前字母的值与该字母的结果之间进行整数除法。

例如2348,C我需要几个?trunc((2348-mod(2348,500))/100)= 3。

然后,我listagg将这封信放在一起3次(利用CONNECT BY该行生成我需要的3行)。最后,我listagg一切都在一起。

有点大,但是大多数是select from dual转换表中的s,我对此真的不能做太多...



0

木炭61 50 46字节

NνA⁰χWφ«W¬‹νφ«§MDCLXVIχA⁻νφν»A⁺¹χχA÷φ⎇﹪χ²¦²¦⁵φ

在线尝试!

说明:

Nν                   Take input as number and assign it to ν
A⁰χ                  Let χ=0
Wφ«                  While φ>0 (φ has a predefined value of 1000)
    W¬‹νφ«               While v>=φ 
        §MDCLXVIχ             Take the char from string "MDCLXVI" at position χ
        A⁻νφν»               Let ν=ν-φ
    A⁺¹χχ                Increment χ
    A÷φ⎇﹪χ²¦²¦⁵φ        If χ is odd, divide φ by 5, else divide φ by 2
  • 感谢Neil,节省了4个字节,而我仍在尝试弄清楚如何继续他的评论的第二部分。

1
Nν是一个字节短于ANν¬‹是一个字节比中减去1而变短,如果使用÷(IntDivide)代替(划分),则可以使用φ作为外循环条件。但是,我认为您可以通过MDCLXVI直接循环来将其减少到40个字节。
尼尔

@Neil,当然,我很傻,试图理解为什么我可以使用“不少于”时没有“大于或等于”运算符。使用整数除法非常巧妙的技巧。现在让我花点时间考虑一下您的评论的最后一部分……
查理(Charlie)

我改进了字符串循环的想法,并将其作为单独的答案与@xnor的Python答案端口一起发布,事实证明它的长度是相同的。
尼尔

0

C ++,272字节

#include <cstdio>
#include <map>
std::map<int,char> m = {{1000,'M'},{500,'D'},{100,'C'},{50,'L'},{10,'X'},{5,'V'},{1,'I'}};
int main(){unsigned long x;scanf("%d",&x);for(auto i=m.rbegin();i!=m.rend();++i)while(x>=i->first){printf("%c", i->second);x=x-i->first;}return 0;}

0

C,183字节

#include <stdio.h>
int v[]={1000,500,100,50,10,5,1};
char*c="MDCLXVI";
int main(){int x;scanf("%d",&x);for(int i=0;i<sizeof v/sizeof(int);i++)for(;x>=v[i];x-=v[i])putc(c[i],stdout);}

与以前相同的算法,只是使用普通的c数组而不是std :: map,部分受@xnor的答案启发,并使用字符串存储字母。



0

Common Lisp,113个字节

这是一个匿名函数,将结果作为字符串返回。

(lambda(value)(setf(values a b)(floor v 1000))(concatenate 'string(format()"~v,,,v<~>"a #\M)(format nil"~@:r"b)))

脱节,带有描述性的变量名和注释:

(defun format-roman (value)
  ;; Get "value integer-divided by 1000" and "value mod 1000"
  (setf (values n_thousands remainder) (floor value 1000))
  (concatenate 'string
               ;; Pad the empty string n_thousands times, using "M" as the 
               ;; padding character
               (format () "~v,,,v<~>" n_thousands #\M)
               ;; Format the remainder using "old-style" Roman numerals, i.e. 
               ;; numerals with "IIII" instead of "IV"
               (format nil "~@:r" remainder)))

CL具有内置的罗马数字格式器。可悲的是,它不适用于大于3999的数字。


0

木炭,34字节

NςA²ξFMDCLXVI«×ι÷ςφA﹪ςφςA÷φξφA÷χξξ

最初基于@CarlosAlego的答案。@xnor的Python解决方案的端口也为34个字节:

NθA⁵ξFIVXLCD«←×ι﹪θξA÷θξθA÷χξξ»←×Mθ

编辑:@xnor的其他Python解决方案的端口原来是33个字节!

NθFMDCLXVI«×ι÷θφA﹪θφθA÷φ⁺׳﹪φ³±¹φ

在线尝试!链接是详细版本的代码。请注意,我之所以使用⁺׳﹪φ³±¹而不是⁻׳﹪φ³¦¹因为deverbosifier当前无法插入分隔符。


1
呵呵,看起来比希腊文更希腊。
亚当
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.