追加、昔ながらの方法


8

概要
古代ローマ人は、ラテン文字を使用した数体系を考案しました。これは、それらを十分に機能させ、現在の文明ではまだ使用されていますが、程度ははるかに小さいです。ローマ人は、その使用時に、多くのアプリケーションで非常に役立つようにするために、これらの数値の使用と操作を学ぶ必要があったでしょう。たとえば、男性が35頭の牛を所有していて、さらに27頭を調達した場合、それらをすべて数える以外に、新しい合計をどのようにして知るのでしょうか。(そうですね、そろばんを使って...)ローマ人ができるなら、きっと私たちもそれを理解することができます。

目的 2つのローマ数字
加算し、どちらかの入力の文字列表現を数値に変換せずに結果出力する、最も短いアルゴリズム/関数/プログラムを記述します。

規則/制約
書式設定における歴史的/中世以前の不整合のため、正書法に関するいくつかの非標準(現代の使用法による)規則の概要を説明します。例として、以下のバリューガイドをご覧ください。

  • I、X、C、およびMの文字は、連続して4回まで繰り返すことができますが、それ以上繰り返すことはできません。D、L、およびVを繰り返すことはできません。
  • ローマの表現で別の文字のすぐ右側にある文字は、左側の文字と同じか、それよりも小さい値になります。
    • 言い換えれば、VIIII == 9しかしIX != 9、そして無効/許可されていません。
  • すべての入力値は2,000(MM)以下になります。Mより大きい数値を表す必要はありません。
  • 上記のルールに従って、すべての入力値は有効なローマ数字になります。
  • ソリューションの一部として、数値を10進数、2進数、またはその他の数値システムに変換することはできません(そのような方法を使用して結果を検証することはできます)。
  • これはコードゴルフなので、最短のコードが勝ちます。

バリューガイド

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

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

さらに説明が必要な場合は、お問い合わせください。


2
XXXXIIII-> 44またはXIIII-> 14?
Paul Richter

1
私は彼が価値ガイドの間違いについて言及していると思います。
grc 2012年

@grcああ。愚かな私...修正。
Gaffi

1
なぜ誰かが別のベースに変換したいのですか?文字列を数値に解析することを禁止するつもりでしたか?
Peter Taylor

@PeterTaylorはい、そうです。
ガフィ

回答:


5

APL(59 56)

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

1行で入力します(つまりXII + XII+必須ではありません)。

編集:シフトを回転して3文字を保存するように変更-回答が5000以上の場合にのみ問題になります。質問では入力値は常に≤2000になるため、これは発生しません。唯一の効果は5000で「オーバーフロー」し、 5000 = 1、5001 = 2など

(私はローマ人がこのようにそれをしたとは本当に思っていません... APLは古代エジプト人にとってもっと何かだと思います:))

説明:

  • :ユーザー入力を取得
  • (N←'MDCLXVI')∘=¨: 'MDCLXVI'をNに格納します。入力文字列の各文字について、その文字が 'MDCLXVI'の1つに対応する場所に1を含むベクトルを返し、それ以外の場合は0を返します。
  • ⊃+/:ベクトルを合計してカプセル化を解除します。これで、各ローマ数字の数に関する情報を含むベクトルができました。つまり、入力がの場合、次のようになりますXXII XIIII
     MDCLXVI
     0 0 0 0 3 0 6
  • これは値を変換しないことに注意してください。
  • {... :... ... }は、if-else構文を使用する関数です。
  • D←7⍴5 2Dベクトル5 2 5 2 5 2 5です。これは、許可されないローマ数字の数です。Iつまり、5 秒の場合は多すぎます。2 V秒の場合も多すぎます。このベクトルはたまたま、各ローマ数字の乗算係数でもあります。つまり、a Vは5 I秒の価値があり、a はX2 V秒の価値があります。

  • ∨/K←⍵≥DK特定の種類のローマ数字が多すぎる場合、1が存在するベクトルです。∨/このベクトルをORします。

  • このベクトルがすべてゼロでない場合:
  • K×D:KにDを乗算します。このベクトルには、ローマ数字が多すぎない場合はゼロがあり、ローマ数字が多い場合はその量が含まれます。
  • ⍵+(1⌽K):Kを1だけ左に回転し、入力に追加します。ローマ数字の数が多すぎると、次の1つが追加されます。
  • ⍵+(1⌽K)-K×D:これを他のベクトルから減算します。その効果は、たとえば6 I秒ある場合、1つ追加Vして4 I秒削除します。
  • :再帰。
  • ⋄⍵Kがすべてゼロの場合、⍵は有効なローマ数字を表すため、returnを返します。
  • N⍴⍨¨:結果のベクトルの各要素に対して、対応するローマ数字をその数だけ作成します。
  • ,/:これらのベクトルを結合して、出力の醜いスペースを取り除きます。

5

Python、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]

入力から1つの文字列を取得します(例:VIII + XIIまたはVIII + XII =)。


3

Perl、132文字

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}

s任意の数の引数を取り、それらを合計する関数を宣言します。非常に簡単です。入力を追加し、すべてをIs に減らし、すぐにローマ数字を復元します。(うまくいけば、これは単項数システムの使用として数えられません!)


3

ルビー、85の 82文字

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

このバージョンは、STDINの入力を単一の文字列(例:)として受け取り、XXIIII + XXXXII出力をSTDOUTに出力します。

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

2つ目は、関数としての実装です。2つ(またはそれ以上)の文字列を取り、合計値を返します。使用法:

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

3

GNU Sed、131文字

:;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、174文字

非常に単純なアルゴリズム-各桁を数え、ループして次の桁へのオーバーフローを処理し、印刷します。
標準入力から読み取ります。のようなものXVI + CXXが機能します(数字以外は無視されるため、これ+は実際には必要ありません)。

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))})

呼び出し:

a("MDCCCCLXXXXVIIII", "MDCCCCLXXXXVIIII")

ungolfedバージョン:

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

私のシステムはかなり初歩的であり、すべてのローマ数字をI両方の数字の一連の数に減らし、それらを結合してから、特定のブロックを回してプロセスを逆にします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)

反復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)

特徴:

  • ゼロ区切りの配列文字列。文字列配列を設定するよりも高速です。
  • 2つの再帰を1つに減らし、特定の正規表現のパラメーターを再計算しました。
  • あなたが棒を突くことができるよりも多くの三項演算子!

入力はプロンプトを介して<first roman number>+<second roman number>(スペースなし)の形式で入力され、アラートの形式で出力されます。

例えば

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

1

VBA、187文字

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

oあなたの缶がそれの割り当ておよび評価を取り外し、プラグインすることで3つのバイトを保存し、一度のみ使用されているn Mod rに直接String(関数呼び出し
テイラー・スコット

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)

の3番目のスロットに命令を入れます forオペレーターのセミコロンをいくつか節約できます。

入力を求めるプロンプトが表示されたら、2つの数字を挿入します(+およびスペースは必要ありませんが、それらを入力してもエラーにはなりません)。次に、アラートに合計が表示されます。


0

C ++、319文字

#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;}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.