เครื่องกำเนิดเลขโรมันที่เหมาะที่สุด


21

เป้าหมาย:
เขียนฟังก์ชันที่ใช้ตัวเลขเป็นอินพุตและส่งกลับตัวเลขโรมันแบบสั้นสำหรับหมายเลขนั้นเป็นเอาต์พุต

สัญลักษณ์ตัวเลขโรมัน:

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

สำหรับตัวอย่างของสิ่งที่ฉันหมายถึงเมื่อฉันพูดว่า "เลขโรมันสั้น ๆ " ลองพิจารณาหาตัวเลขโรมันเพื่อเป็นตัวแทนปี 1983 เพราะนั่นคือปีที่ฉันเกิด ทางเลือกหนึ่งคือทำตามวิธีปกติ (10 ตัวอักษร):

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

อีกทางเลือกหนึ่งคือทำด้วยวิธีทางลัด (6 ตัวอักษร):

1983 = MXVIIM = (1,000 - (10 + 10) + 1000 + 3)

คุณรู้ไหมว่าสิ่งนี้หมายความว่าอย่างไร!? !!? ?? ถ้าฉันเป็นโรมันฉันสามารถบันทึกตัวละครได้ 4 ตัวทุกครั้งที่ฉันเขียนวันเกิด! วุ้ยวุ้ย !!

อย่างไรก็ตามก่อนที่ฉันจะก้าวไปข้างหน้าด้วยความตื่นเต้นฉันมีคำถามที่ต้องเขียนดังนั้นฉันจึงควรกำหนดกฎเลขโรมันสั้น ๆ เพื่อให้เราทุกคนอยู่ในหน้าเดียวกัน:

กฎเลขโรมันระยะสั้น:

  1. พิจารณาสัญลักษณ์จากซ้ายไปขวาเสมอจนกว่าจะไม่มีตัวอักษรอื่น ๆ ให้พิจารณาอีก
  2. หากไม่มีสัญลักษณ์ที่มีมูลค่าสูงกว่าทางด้านขวาของสัญลักษณ์ปัจจุบัน:
    • เพิ่มค่าของสัญลักษณ์ปัจจุบันให้กับผลรวมการทำงานของตัวเลขโรมันนี้
  3. หากมีสัญลักษณ์ที่มีมูลค่าสูงกว่าทางด้านขวาของสัญลักษณ์ที่คุณกำลังพิจารณา:
    • ค้นหาสัญลักษณ์ที่มีค่าสูงสุดขวาสุดทางด้านขวาของสัญลักษณ์ปัจจุบัน
    • พิจารณาตัวละครทุกตัวจนถึงสัญลักษณ์นั้นเป็นเลขโรมันตัวเดียว
    • คำนวณค่าของเลขโรมันนั้นโดยใช้ขั้นตอนเหล่านี้
    • ลบค่าของเลขโรมันนั้นจากผลรวมสะสมของเลขโรมันนี้
    • ย้ายไปที่สัญลักษณ์ถัดไปหลังจากกลุ่มที่คุณเพิ่งพิจารณา
  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 (ที่เหมาะสมลบหนึ่งหมื่นบาทถ้วน) และ 3000 แล้วสรุปความยาวลักษณะของเลขโรมันเหล่านี้จะได้รับของคุณtotalCharacterCount นี่คือรหัสเทียมบางส่วนเพื่อชี้แจง:

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

  4. รอบชิงชนะเลิศต่ำสุดคะแนนชนะ!

หมายเหตุ: เนื่องจากจำนวน totalCharacter จะอยู่ในหลักหมื่น + อัลกอริทึมที่มีความยาวอักขระควรเป็นลำดับความสำคัญสูงสุด คะแนนการเล่นกอล์ฟเป็นเพียงตัวผูกไท่ในกรณีที่ผู้ใช้หลายคนค้นหาอัลกอริธึมหรืออัลกอริธึมที่เหมาะสมที่สุดซึ่งอยู่ใกล้กัน

ขอให้โชคดีและสนุกกับการฉลอง MMXII ของคุณในคืนพรุ่งนี้ !!!


1
เยี่ยมมาก! อย่างไรก็ตามคุณสามารถยกตัวอย่างลักษณะของการจดชวเลขโรมันเชิงลบได้อย่างไร จะDDDDMยืนหยัดเพื่อ-1000?
pimvdb

@pvdvdb คุณเข้าใจแล้ว!
Briguy37

คำถามเกี่ยวกับกรณีพิเศษศูนย์: ""อนุญาตให้เป็นศูนย์หรือเราต้องใช้VVXหรืออะไรที่เทียบเท่า?
โฮเวิร์ด

@ วิธี: คำถามที่ดีฉันไม่ได้คิดอย่างนั้น! ฉันได้เพิ่มเลขโรมันกฎ 4 ที่ชี้แจงกรณีนี้
Briguy37

1
"ค้นหาสัญลักษณ์ที่มีมูลค่าสูงสุดขวาสุดทางด้านขวาของสัญลักษณ์ปัจจุบัน" - ซึ่งชนะรางวัลขวาสุดหรือมูลค่าสูงสุด? นั่นคือIXV = -(-1 + 10) + 5 = -4(Right Right ชนะ) หรือIXV = -1 + 10 + 5 = 14(Win-Values)
Keith Randall

คำตอบ:


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

ซึ่งใช้เวลาประมาณหนึ่งนาที


5

รหัส C ++, 345 ตัวอักษร, ตัวเลข 1,921 ตัวเลขโรมัน = 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;}}}}

deobfuscated เล็กน้อยพร้อมคนขับ:

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 ฐาน (หลักแรกคือ s% 7, หลักที่สองคือ s / 7% 7, ... ) แต่ละหลักถูกเข้ารหัสด้วย I = 0, V = 1, ... , M = 6 fที่ไม่นับไปได้สตริงเลขโรมันแรงเดรัจฉานจะหาคนที่ประเมินVn

จำนวนรวมของตัวเลขโรมันเป็นจำนวนที่ดีที่สุด เลขโรมันที่ยาวที่สุดที่ต้องการสำหรับ [-1000,3000] คือ 11 หลัก (เช่น -827 = CMDDMLXXIII) ซึ่งใช้เวลาประมาณ 5 นาทีในเครื่องของฉัน


รอสักครู่ที่ไม่ทำงานตามที่ระบุไว้ โปรแกรมของคุณจะช่วยให้เช่นเป็นคำตอบLMCLXXIII -777ฉันอ่านว่าเป็น-50+1000-100+50+10+10+3 = 923 ≠ -777เพียงกับ "ขวาสุดสูง -valued" แทน " สูงสุด " -777ไม่ได้ให้ แต่นั่นเป็นเพียงสิ่งที่คุณถามในความคิดเห็น!
หยุดหมุนทวนเข็มนาฬิกาเมื่อ

@leftaroundabout: แน่นอนว่าคุณพูดถูก ฉันจะแก้ไข แต่ไม่มีเวลาตอนนี้ ...
Keith Randall

@leftaroundabout: ตกลงแก้ไขทั้งหมดแล้ว
Keith Randall

เอาล่ะ มันไม่ดีที่สุด แต่ในเวลานี้ (เช่นให้VVVXIสำหรับ-4เมื่อIXVXเป็นจริงสั้นที่ผมเพิ่งสังเกตเห็น) - แต่ที่สมบูรณ์ตามกฎหมาย
หยุดหมุนทวนเข็มนาฬิกา

@leftaroundabout: ตกลงแก้ไขอีกครั้ง หวังว่ามันคือแก้ไขเวลานี้ ...
คี ธ แรนดัล

2

Ruby, 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.