最適な短縮形ローマ数字ジェネレータ


21

目標:
数値を入力として受け取り、その数値の短縮ローマ数字を出力として返す関数を作成します。

ローマ数字記号:

Symbol  Value
I       1
V       5
X       10
L       50
C       100
D       500
M       1,000

「速記ローマ数字」と言うときの意味の例として、1983年を表すローマ数字を見つけることを考えてみましょう。それは私が生まれた年だからです。1つのオプションは、これを通常の方法(10文字)で行うことです。

1983 = MCMLXXXIII =(1000-100 + 1000 + 50 + 30 + 3)

もう1つのオプションは、簡単な方法(6文字)で行うことです。

1983 = MXVIIM =(1000-(10 + 10)+ 1000 + 3)

これが何を意味するか知っていますか?!?!! ?? 私がローマ人だったら、生年月日を書くたびに4文字を節約できたでしょう!うおう!

しかし、興奮する前に、書くべき質問があります。したがって、おそらく、同じページにいるように、速記のローマ数字のルールを定義する必要があります。

ショートハンドローマ数字ルール:

  1. 考慮すべき文字がなくなるまで、シンボルを常に左から右に検討してください。
  2. 現在のシンボルの右側に、より高い値のシンボルがない場合:
    • 現在のシンボルの値をこのローマ数字の積算合計に追加します。
  3. 検討しているシンボルの右側に、より高い値のシンボルがある場合:
    • 現在のシンボルの右にある右端の最高値のシンボルを見つけます
    • その記号までのすべての文字を1つのローマ数字と見なします
    • これらの手順を使用して、そのローマ数字の値を計算します
    • このローマ数字の積算合計からそのローマ数字の値を引きます。
    • 検討したグループの次の記号に移動します
  4. 各ローマ数字には、少なくとも1つの記号が必要です。
  5. それでおしまい!これらのルールに従うものはすべて受け入れられます!

例:

IIIIV = (-(1+1+1+1)+5) = 1  //Don't ask me why you'd want to do this!  

VVX = (-(5+5) + 10) = 0  //Who said you couldn't represent 0 with roman numerals?!!?

VVXM = (-(-(5+5) + 10) + 1000) = 1000  //Again...don't ask me why you'd want to do this!

MXIIXMI = (1000-(10-(1+1)+10)+1000+1) = 1983  //Ahhh...such a great year :)

質問ルール:

  1. 上記のルールを使用して、入力として単一の数値を受け取り、その数値のローマ数字を出力として返す関数を作成します。この関数のcodeGolfScoreを計算します。

    example input: 2011
    example possible output: MMXI
    another possible output: MMVVIVV     //(2000 + 10 - 4 + 5) 
    
  2. ルール1の関数を使用して、-1000(そう、NEGATIVE 1000)と3000の間のローマ数字を生成します。次に、これらのローマ数字の文字の長さを合計して、totalCharacterCountを取得します。明確にするための擬似コードを次に示します。

    totalCharacterCount = 0;
    for(currentNumber = -1000; currentNumber <= 3000; currentNumber++){
        totalCharacterCount += getRomanNumeral(currentNumber).length;
    }
    return totalCharacterCount;
    
  3. finalScore = codeGolfScore + totalCharacterCount

  4. 最も低いfinalScoreが勝ちます!

注:totalCharacterカウントは1万+以上になるため、文字長アルゴリズムが最優先されるはずです。コードゴルフのスコアは、複数のユーザーが互いに最適なアルゴリズムを見つけた場合のタイブレークです。

明日はMMXIIのお祝いをお楽しみください!!!


1
素晴らしい仕事です!しかし、ネガティブなローマの速記がどのように見えるかの例を挙げていただけますか?のDDDDM-1000
pimvdb

@pimvdbわかった!
Briguy37

特別な場合のゼロに関する質問:ゼロは""許可されていますか、それともVVX同等のものを使用する必要がありますか?
ハワード

@ハワード:素晴らしい質問、私はそれを考えていませんでした!その場合を明確にするために、ローマ数字ルール4を追加しました。
Briguy37

1
「右端の最高値のシンボルを現在のシンボルの右側に配置します」-右端または最高値のどちらが勝ちますか?すなわち、IXV = -(-1 + 10) + 5 = -4(右端の勝ち)、またはIXV = -1 + 10 + 5 = 14(最高価値の勝ち)ですか?
キースランドール

回答:


5

Haskell、25637(= 268 + 25369)26045(= 222 + 25823)

r 0="VVX"
r n=s(zip[1000,500,100,50,10,5]"MDCLXV")n ξ
ξ='ξ'
s[]q f
 |q<0=s[](5-q)f++"V"
 |q<1=""
 |r<-q-1='I':s[]r f
s ω@((v,a):l)q f
 |q>=v,f/=a=a:s ω(q-v)ξ
 |f==a,γ<-'I':a:s l(q-v+1)ξ,η γ<η(s l q ξ)=γ
 |f==ξ,γ<-s ω(v-q)a++[a],η γ<η(s l q ξ)=γ
 |True=s l q ξ
η=length

例として使用される

GHCi> r 7
"VII"
GHCi> r 39
"XIL"
GHCi> r (-39)
"ICXLC"        --  "LLXILC" in my original version
GHCi> r 1983
"MXVIIM"
GHCi> r 259876
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMCXXIVM"

あなたは簡単に長さの合計を評価することができます

GHCi> sum . map(length.r) $ [-1000..3000]
25369

これには1分ほどかかります。


5

C ++、コードの345文字、25021のローマ数字= 25366

int N[]={1,5,10,50,100,500,1000};int V(int s,int L){if(!L)return 0;int K=0,B,m=s%7+1;for(int k=1,b=7;k<L;k++,b*=7){if(s/b%7>=m){K=k;B=b;m=s/b%7;}}return K?V(s/B,L-K)-V(s%B,K):N[s%7]+V(s/7,L-1);}char r[99];char*f(int n){for(int L=1,B=7,i,j;1;L++,B*=7){for(i=0;i<B;i++){if(V(i,L)==n){for(j=0;j<L;j++){r[j]="IVXLCDM"[i%7];i/=7;}r[L]=0;return r;}}}}

ドライバーで少し難読化を解除しました:

int N[]={1,5,10,50,100,500,1000};
int V(int s,int L){
  if(!L)return 0;
  int K=0,B,m=s%7+1;
  for (int k=1,b=7;k<L;k++,b*=7) {
    if(s/b%7>=m){K=k;B=b;m=s/b%7;}
  }
  return K ? V(s/B,L-K)-V(s%B,K) : N[s%7]+V(s/7,L-1);
}
char r[99];
char *f(int n){
  for(int L=1,B=7;1;L++,B*=7) {
    for(int i=0;i<B;i++) {
      if(V(i,L)==n){
        for(int j=0;j<L;j++) {
          r[j]="IVXLCDM"[i%7];i/=7;
        }
        r[L]=0;
        return r;
      }
    }
  }
}
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
  printf("%s\n", f(atoi(argv[1])));
}

V指定sされた長さのローマ数字文字列の数値を計算しますL。文字列はベース7でエンコードされます(1桁目はs%7、2桁目はs / 7%7、...)。各桁は、I = 0、V = 1、...、M = 6でエンコードされます。 f可能性のあるローマ数字文字列のブルートフォース列挙を行い、にV評価されるものを見つけますn

ローマ数字の合計桁数が最適です。[-1000,3000]に必要な最長のローマ数字は11桁(たとえば-827 = CMDDMLXXIII)であり、私のマシンでは約5分かかります。


少し待ってください。指定されたとおりに動作しません。あなたのプログラムは、例えばLMCLXXIIIへの答えとして与え-777ます。私はそれを「最高」ではなく-50+1000-100+50+10+10+3 = 923 ≠ -777「右端の高い値」でのみ読むと読みました。しかし、それはあなたがコメントで求めたものでした!-777
反時計回りに

@leftaroundabout:もちろんあなたは正しい。私は...それを修正ませんが、今は時間よ
キース・ランドール

@leftaroundabout:OK、すべて修正済み。
キースランドール

大丈夫。それはだではない(例えば与えますけれども、今、最適VVVXIのための-4ときIXVX、私はちょうど気づいたとして、実際に短いです) -それは完全に合法です。
反時計回りに

@leftaroundabout:OK、もう一度修正。うまくいけば、それはこの時点正しいです...
キース・ランドール

2

ルビー、25987(= 164 + 25823)

h=->i,d,v,k{i==0?'':i<v ?(a=h[v-i,x=d[1..-1],v/k,k^7]+d[0];i<0?a:(b=h[i,x,v/k,k^7];a.size<b.size ? a :b)):d[0]+h[i-v,d,v,k]}
r=->i{i==0?'DDM':h[i,'MDCLXVI',1000,2]}

r直接呼び出して結果を取得できます。指定された範囲の合計は、

> (-1000..3000).map{|i|r[i].size}.reduce &:+
25823

これは他のソリューションと同様に最適な合計です。


0

C#23537(639文字のコード+ 22898文字の出力)

class M
{
    public static string R(int n, int? s = new int?())
    {
        var r = "";
        var D = new Dictionary<int, string> {{ 1000, "M"}, { 900, "CM"},{ 800, "CCM"},{ 500, "D"}, { 400, "CD"},{ 300, "CCD"},{100, "C"}, {90, "XC"},{80, "XXC"},{50, "L"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {8, "IIX"}, {5, "V"}, {4, "IV"},{1, "I"}};
        if (n == 0) return "VVX";
        if (n == -1) return "IIIIIIV";
        if (n < 0) return N(n * -1);

        foreach(int k in D.Keys)
        {
            if (s.HasValue && k > s) continue;

            while(k <= n)
            {
                n -= k; 
                r += D[k];
            }
        }

        return r;
    }

    public static string N(int n)
    {
        var D = new Dictionary<int, string> {{1, "I"}, {5, "V"}, {10, "X"}, {50, "L"}, {100, "C"}, { 500, "D"}, {1000, "M"}};

        int i = D.Keys.First(v => v >= n), m = D.Keys.Where(v => v < i).Max();

        return R(n + i, m) + D[i];
    }
}

計算するには:

Enumerable.Range(-1000, 3000).Sum(i => M.R(i).Length);


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