เมื่ออยู่ในกรุงโรมนับเป็นชาวโรมันทำอย่างไร


20

พื้นหลัง

ความท้าทายนี้ได้รับแรงบันดาลใจจากเว็บไซต์นี้ซึ่งเผยแพร่แผนภาพต่อไปนี้:

ป้อนคำอธิบายรูปภาพที่นี่

แผนภาพนี้แสดงให้เราเห็นว่าการแสดงออกของเลขโรมันที่ยาวที่สุดภายใต้ 250 คือ 188

ท้าทาย

สัญลักษณ์มาตรฐานที่ใช้ในการแสดงตัวเลขโรมันส่วนใหญ่มีดังต่อไปนี้: { I, V, X, L, C, D, M} ที่ค่าตัวเลขของตัวละครที่มีM= 1000 D= 500 C= 100 L= 50 X= 10 V= 5 I= 1

ในการท้าทายนี้เป้าหมายของคุณคือให้เป็นจำนวนเต็มบวกnคำนวณจำนวนตัวเลขโรมันที่ถูกต้องที่สามารถนำมาประกอบผ่านการต่อเชื่อมnของสัญลักษณ์มาตรฐาน

จากนั้นโปรแกรมของคุณจะต้องแสดงผลลัพธ์ของการคำนวณนี้!

การป้อนข้อมูล : เป็นจำนวนเต็มบวกn

เอาท์พุท : จำนวนที่ถูกต้องแสดงออกเลขโรมันของความยาวn

กฎสำหรับนิพจน์ตัวเลขโรมัน

แต่เดิมเลขโรมันมีการจับคู่แบบ "เพิ่มเติม" ซึ่งหมายความว่าตัวเลขจะถูกเขียนตามลำดับจากมากไปหาน้อยและผลรวมของค่าของตัวเลขทั้งหมดคือค่าของตัวเลข

ต่อมาต่อมาการจับคู่แบบลบการใช้การวางตัวเลขขนาดเล็กลงด้านหน้าที่ใหญ่กว่าเพื่อที่จะลบส่วนที่เล็กกว่าออกจากขนาดใหญ่ คู่ subtractive IXLไม่สามารถถูกล่ามโซ่เหมือนในการแสดงออกที่ไม่ถูกต้องต่อไปนี้:

ต่อไปนี้เป็นกฎวันที่ทันสมัยสำหรับการจับคู่แบบบวกและแบบลบ

  1. สามารถใช้ I, X และ C เพียงหนึ่งตัวเป็นตัวเลขนำหน้าในส่วนของคู่ลบ
  2. ฉันสามารถวางก่อน V หรือ X ในคู่ลบ
  3. X สามารถวางก่อน L หรือ C ในคู่ที่หักได้
  4. C สามารถวางไว้ก่อน D หรือ M ในคู่ของการลบ
  5. นอกเหนือจากคู่ที่ลบออกตัวเลขจะต้องอยู่ในลำดับถัดลงมา (หมายความว่าหากคุณวางตัวเลขนำหน้าของคู่ลบแต่ละคู่นั้นตัวเลขนั้นจะเรียงตามลำดับจากมากไปน้อย)
  6. M, C และ X ไม่สามารถเท่ากับหรือเกินจากหน่วยที่เล็กกว่า
  7. D, L และ V สามารถปรากฏได้เพียงครั้งเดียวเท่านั้น
  8. เฉพาะ M เท่านั้นที่สามารถทำซ้ำได้ 4 ครั้งขึ้นไป

หมายเหตุเพิ่มเติม

  • เราจะไม่ใช้สัญลักษณ์บาร์ ค่อนข้างเราเพียงแค่เพิ่มMเพิ่มเติมเพื่อแสดงหมายเลขใด ๆ

  • เหล่านี้เป็นกฎเดียวที่เราจะปฏิบัติตามสำหรับตัวเลขโรมันของเรา นั่นหมายความว่าการแสดงออกที่แปลกเช่นIVIจะได้รับการพิจารณาในระบบของเราเช่นกัน

  • โปรดจำไว้ว่าเราไม่นับจำนวนตัวเลขที่มีนิพจน์ความยาวnเนื่องจากบางตัวเลขมีหลายนิพจน์ แต่เรานับจำนวนนิพจน์ที่ถูกต้องเท่านั้น

กรณีทดสอบ

17

231

3105

ฉันตรวจสอบข้างต้นด้วยมือดังนั้นโปรดตรวจสอบอีกครั้งเพื่อตรวจสอบกรณีทดสอบและเพิ่มมากขึ้นถ้าคุณทำได้!

เกณฑ์การชนะ

นี่คือความท้าทายของดังนั้นขอให้สนุก! ฉันจะยอมรับเฉพาะโซลูชันที่สามารถจัดการอินพุตอย่างน้อยจาก 1 ถึง 9 ได้อีกคือโบนัส!

แก้ไข

ตามที่ผู้วิจารณ์ร้องขอค้นหาด้านล่างหรือที่ลิงก์ pastebin นี้ 105 คอมโบที่ฉันนับสำหรับn = 3

III IVI IXI IXV IXX ปกเกล้าเจ้าอยู่หัวสิบสองสิบสี่สิบหก XVI XXI XXXV XI XLV XLX XCI XCV XCX XCD XCL XCC XCC XCC XII LII LIV LIX LIF LVI LXV LXX CII CIV CIX Cix Cix CXV CXX Cixx Cix CDV CDX CMI CMV CMX CML CMC CMD CMM DII DIV DIX DVI DXI DXX DXL DXC MDI MDV MDI MDV MDX MDI MDV MDX MDI MDV MDX MDI MDV MMX MML MMC MMD MMM

แก้ไข 2:

ใช้ที่ไม่แข็งแรงเล่นกอล์ฟต่อไปนี้รหัสเป็นมารยาทของโจนาธานอัลลันเพื่อตรวจสอบผลลัพธ์ของคุณ

แก้ไข 3:

ฉันขอโทษสำหรับข้อผิดพลาดทั้งหมดในการท้าทายนี้ ฉันจะทำให้ดีขึ้นในครั้งต่อไป!


ความคิดเห็นไม่ได้มีไว้สำหรับการอภิปรายเพิ่มเติม การสนทนานี้ได้รับการย้ายไปแชท
Mego

คำตอบ:


3

เรติน่า , 111 ไบต์

~(`.+
*$(CM)CDXCXCXCXLIXIXIXIVII
.(.)
.+¶$$&$¶$$&$1$¶$$&$&¶L`.{0,$+}\b¶D`¶
¶$
¶.+¶$$&$¶$$&I¶L`[A-Z]{$+}\b¶D`¶.+

ลองออนไลน์! นี่คือการเขียนที่สมบูรณ์ที่สุดเท่าที่ผมเข้าใจผิดกฎ 1. หมายความว่าคุณจะสามารถใช้หนึ่งในแต่ละ subtractive I, และX Cคำอธิบาย: ส่วนแรกของสคริปต์ขยายอินพุตเป็นสตริงCMคู่ตามด้วยคู่ลบที่เป็นไปได้อื่น ๆ แต่ละคู่เป็นทางเลือกและอักขระตัวแรกของแต่ละคู่ก็เป็นทางเลือกภายในคู่นั้นเช่นกัน ขั้นตอนที่สามนั้นจะขยายรายการคู่ให้เป็นรายการคำสั่ง Retina ที่รับอินพุตและสร้างสำเนาสามชุดโดยมีตัวเลือกของอักขระที่สองหรือทั้งคู่จากคู่จากนั้นตัดขอบและขจัดผลลัพธ์ซ้ำซ้อน ขั้นตอนสุดท้ายจากนั้นผนวกรหัสเพื่อดำเนินงานขั้นสุดท้าย: ก่อนอื่นเพื่อขยายอินพุตเพื่อเพิ่มสุดท้ายIจากนั้นเพื่อกรองผลลัพธ์ของความยาวผิดจากนั้นซ้ำซ้อนผลลัพธ์และในที่สุดก็จะนับผลลัพธ์ สคริปต์เรตินาที่ได้จะถูกประเมินผล

หมายเหตุ: ในทางทฤษฎี 15 ไบต์จะถูกบันทึกไว้จากจุดสิ้นสุดของเส้นที่ 4 แต่นี้ทำให้สคริปต์ที่ช้าเกินไปที่จะแสดงให้เห็นใน TIO n=1แม้สำหรับ


@JanathanAllan Ah แล้วคุณจะรวมการลบหลายคู่ที่มีตัวเลขนำหน้าเหมือนกันซึ่งผิด
Neil

2
@JanathanAllan เขียนใหม่โดยบังเอิญสำหรับจำนวนไบต์เดียวกันแน่นอน!
Neil

5

Python 2 , 177 168 162 ไบต์

import re,itertools as q
f=lambda n:sum(None!=re.match("^M*(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$",(''.join(m)))for m in q.product('MDCLXVI',repeat=n))

ลองออนไลน์!

ฉันค่อนข้างใหม่ช่วยฉันเล่นกอล์ฟนี้! นี้จะตรวจสอบตัวเลขโรมันที่แท้จริง regex จะต้องมีการปรับเพื่อบัญชีสำหรับกรณีที่แปลก ๆ เช่นIVI

-9 ไบต์ขอบคุณ @Dead Possum!

-6 ไบต์ขอบคุณ @ovs


ใช่ฉันคิดว่ากรณี n = 3 อาจผิดในตัวอย่าง ฉันได้รับ 93 ด้วย^M*(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$
Easton Bornemeier


1
@ โจนาธานอัลลันฉันใช้เวลาประมาณสองวันเพื่อถามเกี่ยวกับการแลกเปลี่ยนทางคณิตศาสตร์ที่พยายามทำให้แน่ใจว่ากฎเหล่านี้สมเหตุสมผล เดาฉันทำไม่ได้พอ :(
อย่าพัน

1
@RushabhMehta นี่เป็นความท้าทายที่จัดรูปแบบได้ดีและสนุกกับการเขียนโปรแกรมอย่ารู้สึกแย่เกี่ยวกับความแตกต่างที่ไม่ดีในโชคชะตาของคำนิยามเลขโรมัน มันเป็นความท้าทายของคุณระบุมันตามที่เห็นสมควร มันใช้งานได้ในแง่อื่นยากกว่า
Easton Bornemeier

1
ดูเหมือนจะไม่ได้คำตอบที่ถูกต้องสำหรับ 3 93แทนที่จะเป็น105
Jo King

3

JavaScript (ES7), 133 ไบต์

แก้ไข : แก้ไขเพื่อให้ตรงกับผลลัพธ์ที่ส่งคืนโดยโจนาธานอัลลันรหัสซึ่งได้รับเป็นการใช้งานอ้างอิงโดย OP


n=>[...Array(m=k=7**n)].reduce(s=>s+/^1*5?4{0,3}3?2{0,3}6?0{0,3}$/.test((--k+m).toString(7).replace(/0[62]|2[34]|4[51]/g,s=>s[1])),0)

ลองออนไลน์!

อย่างไร?

ยังไม่มีข้อความ1

[...Array(m = k = 7 ** n)].reduce(s => … (--k + m).toString(7) …, 0)

จากนี้ไปตัวเลขแต่ละหลักจะถูกตีความเป็นสัญลักษณ์ตัวเลขโรมัน:

0ผม,1M,2X,3L,4,5D,6V

2) เราแทนที่คู่ลบแบบฟอร์มที่ถูกต้องทั้งหมดABด้วยB:

.replace(/0[62]|2[34]|4[51]/g, s => s[1]))  // in the code
.replace(/I[VX]|X[LC]|C[DM]/g, s => s[1]))  // with Roman symbols

ตัวอย่าง:

  • XLIXIV กลายเป็น LXV
  • XIIVกลายเป็นXIVปล่อยให้สิ่งIนั้นจะทำให้การทดสอบครั้งต่อไปล้มเหลว
  • ICยังคงไม่เปลี่ยนแปลงซึ่งยังใบที่ไม่ถูกต้องIในสถานที่

3) เราตรวจสอบว่าสัญลักษณ์ที่เหลืออยู่ในลำดับที่ถูกต้องและไม่ปรากฏเกินเวลาที่อนุญาต:

/^1*5?4{0,3}3?2{0,3}6?0{0,3}$/.test(…)  // in the code
/^M*D?C{0,3}L?X{0,3}V?I{0,3}$/.test(…)  // with Roman symbols

วัวศักดิ์สิทธิ์ฉันไม่ได้คาดหวังว่าอันนี้จะทำในน้อยกว่า 200 ไบต์ในภาษาที่ไม่ลึกลับ! ใจอธิบายว่าวิธีนี้ทำงานอย่างไร
Don Thousand

อย่างไรก็ตามฉันสังเกตเห็นว่าวิธีนี้ใช้ไม่ได้กับ * n *> 4 ใน TIO ซึ่งค่อนข้างโชคร้าย
Don Thousand

@RushabhMehta ฉันได้เพิ่มเวอร์ชันที่ไม่ใช่แบบเรียกซ้ำเพื่อทดสอบค่าที่สูงขึ้น ฉันจะเพิ่มคำอธิบายเมื่อฉันเล่นกอล์ฟนี้เสร็จแล้ว
Arnauld

0

ค, 150 123 ไบต์

ฉันไม่ได้อ่านคำอธิบายอย่างใกล้ชิดพอดังนั้นสิ่งนี้จึงสร้างจำนวนเลขโรมันมาตรฐาน (ที่IVIไม่นับนิพจน์เช่น) เนื่องจากฉันใช้ความพยายามฉันจึงคิดว่าฉันจะแบ่งปันต่อไป

#define F(X) for(X=10;X--;)
x[]={0,1,2,3,2,1,2,3,4,2};f(i,o,a,b,c){for(i++;i--;)F(a)F(b)F(c)o+=i==x[a]+x[b]+x[c];return o;}

ดั้งเดิม (150 ไบต์):

#define F(X) for(X=10;X--;)
i,o,a,b,c,x[]={0,1,2,3,2,1,2,3,4,2};main(){scanf("%i",&i);for(i++;i--;)F(a)F(b)F(c)o+=i==x[a]+x[b]+x[c];printf("%i\n",o);}

1
คุณอนุญาตให้โพสต์การส่งที่ถูกต้องเท่านั้น
Okx

@CurtisBechtel คุณสามารถแก้ปัญหาที่นี่ฉันคิดว่า แต่ฉันจะพยายามแก้ไขเพื่อตอบสนองกฎของความท้าทาย
Don Thousand

1
ฉันคิดว่าคุณสามารถลบช่องว่างระหว่างF(X)และfor(X=10;X--;)
Zacharý
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.