Thêm, cách cổ điển


8

Tổng quan
Người La Mã cổ đại đã nghĩ ra một hệ thống số sử dụng các chữ cái Latinh, phục vụ tốt cho họ và vẫn được sử dụng bởi nền văn minh hiện đại, mặc dù ở mức độ nhỏ hơn nhiều. Trong thời gian sử dụng, người La Mã đã phải học cách sử dụng và thao tác những con số này để được sử dụng nhiều cho nhiều ứng dụng. Ví dụ, nếu một người đàn ông sở hữu 35 con bò và anh ta đã mua thêm 27 con, làm sao anh ta biết tổng số mới ngoài việc đếm tất cả? ( Ok, điều đó và sử dụng bàn tính ... ) Nếu người La Mã có thể làm điều đó, chắc chắn chúng ta cũng có thể tìm ra nó.

Mục tiêu
Viết thuật toán / hàm / chương trình ngắn nhất sẽ cộng hai chữ số La Mã lại với nhau và đưa ra kết quả mà không chuyển đổi biểu diễn chuỗi của một trong hai đầu vào thành một số.

Các quy tắc / ràng buộc
Do sự không nhất quán trong lịch sử / tiền trung cổ trong định dạng, tôi sẽ phác thảo một số quy tắc không chuẩn (theo cách sử dụng hiện đại) cho chỉnh hình. Xem hướng dẫn giá trị dưới đây làm ví dụ.

  • Các chữ cái I, X, C và M có thể được lặp lại tới bốn lần liên tiếp, nhưng không nhiều hơn. D, L và V không bao giờ có thể lặp lại.
  • Chữ ngay bên phải của một chữ cái khác trong đại diện La Mã sẽ có cùng giá trị hoặc ít hơn so với bên trái của nó.
    • Nói cách khác, VIIII == 9nhưng IX != 9không hợp lệ / không được phép.
  • Tất cả các giá trị đầu vào sẽ là 2.000 (MM) trở xuống; không đại diện cho số lớn hơn M là cần thiết.
  • Tất cả các giá trị đầu vào sẽ là một số La Mã hợp lệ, theo các quy tắc trên.
  • Bạn không được chuyển đổi bất kỳ số nào thành số thập phân, nhị phân hoặc bất kỳ hệ thống số nào khác như một phần của giải pháp của bạn (bạn được hoan nghênh sử dụng phương pháp như vậy để XÁC MINH kết quả của bạn).
  • Đây là mã golf, vì vậy mã ngắn nhất sẽ thắng.

Hướng dẫn giá trị

Symbol        Value
I             1
II            2
III           3
IIII          4
V             5
VIIII         9
X             10
XIIII         14
XXXXIIII      44
L             50
LXXXXVIIII    99
C             100
D             500
M             1,000

Ví dụ

XII + VIII = XX (12 + 8 = 20)
MCCXXII + MCCXXII = MMCCCCXXXXIIII (1,222 + 1,222 = 2,444)
XXIIII + XXXXII = LXVI (24 + 42 = 66)

Nếu cần làm rõ thêm, xin vui lòng hỏi.


2
XXXXIIII -> 44 hoặc XIIII -> 14?
Paul Richter

1
Tôi nghĩ rằng anh ấy đang đề cập đến một sai lầm trong hướng dẫn giá trị.
grc

@grc ơi. Ngớ ngẩn với tôi ... Đã sửa.
Gaffi

1
Tại sao bất cứ ai cũng muốn chuyển đổi sang một cơ sở khác? Bạn thực sự có nghĩa là cấm phân tích chuỗi thành một số?
Peter Taylor

@PeterTaylor Vâng, đúng vậy.
Gaffi

Câu trả lời:


5

APL ( 59 56)

,/N⍴⍨¨{∨/K←⍵≥D←7⍴5 2:∇⍵+(1⌽K)-K×D⋄⍵}⊃+/(N←'MDCLXVI')∘=¨⍞

Nhập vào một dòng (nghĩa là XII + XII, mặc dù +không cần thiết).

Chỉnh sửa: thay đổi shift để xoay để lưu ba ký tự - nó chỉ quan trọng khi câu trả lời 5000, điều này không bao giờ xảy ra vì câu hỏi cho biết các giá trị đầu vào sẽ luôn là ≤ 2000. Hiệu ứng duy nhất hiện tại là "tràn" ở 5000, cho 5000 = 1, 5001 = 2, v.v.

(Tôi thực sự không nghĩ rằng người La Mã đã làm theo cách này ... APL là thứ gì đó hơn đối với người Ai Cập cổ đại tôi nghĩ :))

Giải trình:

  • : nhận đầu vào của người dùng
  • (N←'MDCLXVI')∘=¨: lưu trữ 'MDCLXVI' trong N. Trả về, cho mỗi ký tự của chuỗi đầu vào, một vectơ có 1 ở vị trí mà ký tự tương ứng với một trong 'MDCLXVI' và 0 khác.
  • ⊃+/: Tính tổng các vectơ và khử. Bây giờ chúng ta có một vectơ với thông tin về số chữ số La Mã chúng ta có. Tức là, nếu đầu vào là XXII XIIII, bây giờ chúng ta có:
     MDCLXVI
     0 0 0 0 3 0 6
  • Lưu ý rằng đây không phải là chuyển đổi các giá trị.
  • {... :... ... }là một hàm với cấu trúc if-other.
  • D←7⍴5 2: Dlà vectơ 5 2 5 2 5 2 5. Đây là số lượng chữ số La Mã không được phép. Tức là nếu bạn có 5 Igiây thì quá nhiều và nếu bạn có 2 Vgiây thì cũng quá nhiều. Vectơ này cũng là hệ số nhân cho mỗi chữ số La Mã, tức là a Vcó giá trị 5 Igiây và an Xcó giá trị 2 Vgiây.

  • ∨/K←⍵≥D: Klà vectơ trong đó có 1 nếu chúng ta có quá nhiều chữ số La Mã thuộc một loại nào đó. ∨/ORs vector này với nhau.

  • Nếu vectơ này không phải là tất cả các số 0:
  • K×D: Nhân K với D. Vectơ này có các số 0 trong đó chúng ta không có quá nhiều chữ số La Mã và số lượng chữ số La Mã nơi chúng ta làm.
  • ⍵+(1⌽K): Xoay K sang trái 1 và thêm nó vào đầu vào. Đối với mỗi chữ số La Mã chúng ta có quá nhiều, số này sẽ thêm một trong số cao hơn tiếp theo.
  • ⍵+(1⌽K)-K×D: Trừ cái này khỏi vector khác. Hiệu quả là, ví dụ nếu bạn có 6 Igiây, nó sẽ thêm một Vvà xóa 4 Igiây.
  • : Tái diễn.
  • ⋄⍵: Nhưng nếu Klà tất cả các số 0, thì đại diện cho một số La Mã hợp lệ, vì vậy hãy trả về.
  • N⍴⍨¨: Đối với mỗi phần tử của vectơ kết quả, tạo nhiều chữ số La Mã tương ứng.
  • ,/: Nối các vectơ này lại với nhau để loại bỏ các khoảng trống xấu xí ở đầu ra.

5

Con trăn, 100

s="IVXLCDM"
r=raw_input()
a=""
i=2
u=0
for c in s:r+=u/i*c;i=7-i;u=r.count(c);a+=u%i*c
print a[::-1]

Lấy một chuỗi từ đầu vào (ví dụ VIII + XIIhoặc VIII + XII =).


3

Perl, 132 ký tự

sub s{@a=VXLCDM=~/./g;@z=(IIIII,VV,XXXXX,LL,CCCCC,DD);$r=join"",@_;
$r=~s/$a[-$_]/$z[-$_]/gfor-5..0;$r=~s/$z[$_]/$a[$_]/gfor 0..5;$r}

Khai báo hàm slấy bất kỳ số lượng đối số nào và tính tổng chúng. Khá đơn giản: nó nối thêm đầu vào, giảm mọi thứ thành Is và sau đó khôi phục ngay các chữ số La Mã. (Hy vọng điều này không được tính là sử dụng hệ thống số đơn nguyên!)


3

Ruby, 85 82 ký tự

gets;r=0;v=5;puts"IVXLCDM".gsub(/./){|g|r+=$_.count g;t=r%v;r/=v;v^=7;g*t}.reverse

Phiên bản này lấy đầu vào trên STDIN dưới dạng một chuỗi (ví dụ XXIIII + XXXXII) và in đầu ra thành STDOUT.

f=->*a{r=0;v=5;"IVXLCDM".gsub(/./){|g|r+=(a*'').count g;t=r%v;r/=v;v^=7;g*t}.reverse}

Cái thứ hai là một thực hiện như là một chức năng. Lấy hai (hoặc nhiều) chuỗi và trả về các giá trị tổng. Sử dụng:

puts f["XXIIII", "XXXXII"]     # -> LXVI

3

GNU Sed, 131 ký tự

:;s/M/DD/;s/D/CCCCC/;s/C/LL/;s/L/XXXXX/;s/X/VV/;s/V/IIIII/;t;s/\W//g;:b;s/IIIII/V/;s/VV/X/;s/XXXXX/L/;s/LL/C/;s/CCCCC/D/;s/DD/M/;tb

1

Python, ký tự 174

Một thuật toán rất đơn giản - đếm từng chữ số, vòng lặp để xử lý tràn sang phần tiếp theo, in.
Đọc từ đầu vào tiêu chuẩn. Một cái gì đó XVI + CXXsẽ hoạt động (bỏ qua mọi thứ trừ chữ số, vì vậy +không thực sự cần thiết).

x="IVXLCDM"
i=raw_input()
d=dict((c,i.count(c))for c in x)
for c in x:
    n=2+3*(c in x[::2])
    if d[c]>=n:d[c]-=n;d[x[x.find(c)+1]]+=1
print"".join(c*d[c]for c in reversed(x))

1

Scala 150

val c="IVXLCDM"
def a(t:String,u:String)=((t+u).sortBy(7-c.indexOf(_))/:c.init)((s,z)=>{val i=c.indexOf(z)+1
s.replaceAll((""+z)*(2+i%2*3),""+c(i))})

cầu nguyện:

a("MDCCCCLXXXXVIIII", "MDCCCCLXXXXVIIII")

Phiên bản chưa được chỉnh sửa:

val c = "IVXLCDM"
def add (t:String, u:String) = (
  (t+u).  // "MDCCCCLXXXXVIIIIMDCCCCLXXXXVIIII"
  sortBy(7-c.indexOf(_)) // MMDDCCCCCCCCLLXXXXXXXXVVIIIIIIII
  /: // left-fold operator to be used: (start /: rest) ((a,b)=> f (a,b)) 
  c.init) /* init is everything except the rest, so c.init = "IVXLCD"
    (because M has no follower to be replaced with */
  ((s, z) => { /* the left fold produces 2 elements in each step, 
    and the result is repeatedly s, on initialisation 
    MMDDCCCCCCCCLLXXXXXXXXVVIIIIIIII 
    and z is the iterated element from c.init, namely I, V, X, L, C, D
    in sequence */
    val i = c.indexOf (z) + 1 // 1, 2, ..., 7
    /* i % 2 produces 1 0 1 0 1 0
       *3 => 3 0 3 0 
       +2 => 5 2 5 2 
       (""+ 'I') * 5 is "IIIII", ("" + 'V') * 2 is "VV", ...
       ""+c(i) is "V", "X", ...
    */ 
    s.replaceAll (("" + z) * (2+i%2*3), "" + c (i))
    }
  )

1

JavaScript 195 179

Hệ thống của tôi khá thô sơ, giảm tất cả các chữ số La Mã thành một chuỗi Icho cả hai số, nối chúng lại và sau đó đảo ngược quá trình biến một số khối nhất định Ithành các phiên bản lớn hơn tương ứng của chúng ...

Lặp lại 1 a="IIIII0VV0XXXXX0LL0CCCCC0DD0M".split(0);d=b=>x.replace(g=RegExp((c=z)>b?a[c][0]:a[c],"g"),c>b?a[b]:a[b][0]);x=prompt().replace("+","");for(z=6;0<z;z--)x=d(z-1);for(z=0;6>z;z++)x=d(z+1);alert(x)

Lặp lại 2 a="IIIII0VV0XXXXX0LL0CCCCC0DD0M".split(0);x=prompt().replace("+","");for(z=-6;6>z;z++)b=0>z?-z:z,c=0>z?~z:z+1,x=x.replace(g=RegExp(b>c?a[b][0]:a[b],"g"),b>c?a[c]:a[c][0]);alert(x)

Đặc trưng:

  • Chuỗi phân tách không giới hạn, nhanh hơn so với thiết lập mảng chuỗi.
  • Giảm hai lần truy cập thành một, và tính toán lại các tham số cho regex cụ thể.
  • Nhiều nhà khai thác ternary hơn bạn có thể chọc vào!

Đầu vào được nhập thông qua lời nhắc dưới dạng <first roman number>+<second roman number>(không có dấu cách), đầu ra ở dạng cảnh báo.

ví dụ

XVI+VII // alert shows XXIII, correct!
MCCXXXIIII+DCCLXVI // alert shows MM, also correct!

1

VBA, 187 ký tự

Function c(f,s)
a=Split("I,V,X,L,C,D,M",",")
z=f & s
For i=0 To 6
x=Replace(z,a(i),"")
n=Len(z)-Len(x)+m
r=IIf(i Mod 2,2,5)
o=n Mod r
m=Int(n/r)
c=String(o,a(i)) & c
z=x
Next
End Function

ochỉ được sử dụng một lần, bạn có thể lưu 3 byte bằng cách xóa phân công và đánh giá của nó và cắm n Mod rtrực tiếp vào lệnh String(gọi hàm
Taylor Scott

1

JavaScript, 190

x=prompt(r=[]);p=RegExp;s="MDCLXVI";for(i=-1;++i<7;){u=x.match(new p(s[i],'g'));if(u)r=r.concat(u)};for(r=r.join("");--i>0;){r=r.replace(new p(s[i]+'{'+(i%2==0?5:2)+'}','g'),s[i-1])}alert(r)

Đặt một số hướng dẫn bên trong khe thứ ba của fortoán tử cho phép tôi lưu một số dấu chấm phẩy!

Khi đầu vào nhắc nhở, bạn chèn hai số ( +không và khoảng trắng là không cần thiết, nhưng nếu bạn đặt chúng, bạn sẽ không gặp lỗi). Sau đó, cảnh báo cho bạn thấy tổng.


0

C ++, 319 ký tự

#define A for(j=0;j<
#define B .length();j++){ 
#define C [j]==a[i]?1:0);}
#include <iostream>
int main(){std::string x,y,s,a="IVXLCDM";int i,j,k,l,m=0,n;std::cin>>x>>y;for(i=0;i<7;i++){k=0;l=0;A x B k+=(x C A y B l+=(y C n=k+l+m;m=(n)%(i%2?2:5);for(j=0;j<m;j++){s=a[i]+s;}m=(n)/(i%2?2:5);}std::cout<<s<<"\n";return 0;}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.