เศษที่ใกล้ที่สุด


24

งาน:

โปรแกรมของคุณจะได้รับที่เหมาะสมในเชิงบวกส่วนที่เรียบง่าย<numerator>/<denominator>ในรูปแบบ

สำหรับข้อมูลนี้มันจะต้องพบสองเศษส่วน

  1. ส่วนที่น้อยกว่าอินพุต
  2. ส่วนที่มากกว่าอินพุต

เศษส่วนทั้งสองจะต้องมีตัวส่วนที่ต่ำกว่าอินพุต ของเศษส่วนที่เป็นไปได้ทั้งหมดพวกเขาควรมีความแตกต่างต่ำสุดกับอินพุต

เอาท์พุท:

ผลลัพธ์ของโปรแกรมของคุณจะต้อง:

  • <numerator>/<denominator>เศษส่วนที่มีขนาดเล็กกว่าการป้อนข้อมูลในรูปแบบ
  • ตามด้วยอักขระเว้นวรรค (ASCII-code 32)
  • <numerator>/<denominator>ตามด้วยส่วนที่มากกว่าการป้อนข้อมูลในรูปแบบที่

ดังนี้

«fraction that is < input» «fraction that is > input»

กฎ:

  • เศษส่วนทั้งหมดออกมาจะต้องเป็นในแง่ต่ำสุด
  • เศษส่วนทั้งหมดที่ส่งออกจะต้องเป็นเศษส่วนที่เหมาะสม
  • หากไม่มีเศษส่วนที่เหมาะสมที่เป็นไปได้ที่กฎอนุญาตคุณต้องส่งออก0แทนการป้อนเข้า <และ1แทนเศษส่วน>
  • คุณสามารถเลือกได้ว่าคุณต้องการรับเศษส่วนเป็นอาร์กิวเมนต์บรรทัดคำสั่ง (เช่นyourprogram.exe 2/5) หรือพร้อมท์สำหรับการป้อนข้อมูลของผู้ใช้
  • คุณอาจจะสมมติว่าโปรแกรมของคุณจะไม่ได้รับอินพุตที่ไม่ถูกต้อง
  • รหัสที่สั้นที่สุด (เป็นไบต์ในภาษาใดก็ได้) จะชนะ
  • อาร์กิวเมนต์บรรทัดรับคำสั่งที่ไม่ได้มาตรฐานใด ๆ (อาร์กิวเมนต์ที่ไม่จำเป็นต้องใช้ในการเรียกใช้สคริปต์) จะนับรวมไปยังจำนวนอักขระทั้งหมด

  • โปรแกรมของคุณต้องไม่ทำอะไร:

    • ขึ้นอยู่กับทรัพยากรภายนอกใด ๆ
    • ขึ้นอยู่กับการมีชื่อไฟล์เฉพาะ
    • เอาต์พุตสิ่งอื่นนอกเหนือจากเอาต์พุตที่ต้องการ
    • ใช้เวลารันนานเป็นพิเศษ หากโปรแกรมของคุณใช้เวลาเศษเสี้ยวด้วยเศษ 6 หลักและตัวหาร (เช่น179565/987657) ในคอมพิวเตอร์ของผู้ใช้ตามบ้านโดยเฉลี่ยแสดงว่าโปรแกรมนั้นไม่ถูกต้อง
    • เศษส่วนการส่งออกที่มี0ในฐานะส่วน คุณไม่สามารถหารด้วยศูนย์
    • เศษส่วนเอาต์พุตที่มี0เป็นตัวเศษ โปรแกรมของคุณจะต้องแสดงผล0แทนเศษส่วน
    • ลดเศษส่วนที่ป้อนเข้า หากเศษส่วนที่ระบุเป็นอินพุตลดลงคุณต้องใช้เศษส่วนที่ป้อนเข้า
  • โปรแกรมของคุณจะต้องไม่ถูกเขียนในภาษาการเขียนโปรแกรมซึ่งไม่มีผู้แปล / ล่ามสาธารณะที่มีอยู่ก่อนที่จะโพสต์ความท้าทายนี้

ตัวอย่าง:

อินพุต: 2/5
เอาต์พุต: 1/3 1/2

อินพุต: 1/2
เอาต์พุต: 0 1

อินพุต: 5/9
เอาต์พุต: 1/2 4/7

อินพุต: 1/3
เอาต์พุต: 0 1/2

อินพุต: 2/4
เอาต์พุต: 1/3 2/3

อินพุต: 179565/987657
เอาต์พุต: 170496/937775 128779/708320


1
ตัวอย่างแรกของคุณไม่ตรงกับข้อกำหนด: เศษส่วนทั้งสองต้องมีตัวส่วนที่ต่ำกว่าอินพุท
Howard

1
1/3 1/2ตัวอย่างแรกออกควรจะเป็น
Heiko Oberdiek

@HeikoOberdiek คุณพูดถูก คงที่
user2428118

1
กำหนด "คอมพิวเตอร์ของผู้ใช้ตามบ้านโดยเฉลี่ย" 90 วินาทีสำหรับเครื่อง 1.6GHz Intel Atom เป็นที่ยอมรับหรือไม่?
John Dvorak

2
ตัวอย่างสุดท้ายของคุณไม่ถูกต้อง ส่วนอินพุทเท่ากับเศษส่วนแรกของเอาท์พุท
DavidC

คำตอบ:


3

Sage - 119 117

x,X=map(int,raw_input().split('/'))
a=0
A=c=C=1
while C<X:exec("ab,,AB"[c*X>C*x::2]+"=c,C");c=a+b;C=A+B
print a/A,b/B

Sage ต้องการเฉพาะในบรรทัดสุดท้ายซึ่งดูแลเอาต์พุต ทุกอย่างอื่นยังใช้งานได้ใน Python

แทนที่raw_input()ด้วยsys.argv[1]เพื่อให้อินพุตอ่านจากอาร์กิวเมนต์บรรทัดคำสั่งแทนพร้อมต์ สิ่งนี้จะไม่เปลี่ยนจำนวนตัวอักษร (ไม่ทำงานใน Python โดยไม่ต้องนำเข้าsysก่อน)

สิ่งนี้จะสร้างลำดับFareyตามลำดับซ้ำโดยใช้สื่อกลางขององค์ประกอบที่มีอยู่ แต่ จำกัด ตัวเองให้องค์ประกอบเหล่านั้นใกล้เคียงกับอินพุต จากมุมมองอื่นมันรันการค้นหาแบบซ้อนช่วงบนลำดับ Farey ที่เกี่ยวข้อง

มันประมวลผลตัวอย่างทั้งหมดอย่างถูกต้องในเวลาไม่ถึงวินาทีบนเครื่องของฉัน

นี่คือเวอร์ชั่นที่ไม่ได้รับการอวด:

x,X = map(Integer,sys.argv[1].split('/'))
x = x/X
a = 0
c = b = 1
while c.denominator() < X:
    if c > x:
        b = c
    else:
        a = c
    c = ( a.numerator() + b.numerator() ) / ( a.denominator() + b.denominator() )
print a,b

ฉันกลัวอยู่แล้วว่าฉันจะไม่ได้รับผลงานใหม่ ๆ จากค่าหัวนี้ การทำงานที่ดี.
user2428118

เคล็ดลับที่ดีกับexec!
xnor

เนื่องจากคำตอบเดียวที่ถูกส่งภายในระยะเวลาของรางวัลฉันขอมอบรางวัลให้คุณ ขอแสดงความยินดี
user2428118

ฉันเพียงแค่การแก้ไขข้อผิดพลาดในหนึ่งในตัวอย่าง คุณอาจต้องการแก้ไขการส่งของคุณ (แม้ว่าจะใช้เวลาครึ่งปีนับตั้งแต่ที่คุณส่งมา)
user2428118

12

Python 2.7 - 138

x,y=n,d=map(int,raw_input().split('/'))
while y:x,y=y,x%y
def f(p,a=d):
 while(a*n+p)%d:a-=1
 print`(a*n+p)/d`+('/'+`a`)*(a>1),
f(-x);f(x)

ฉันเริ่มต้นด้วยวิธีการแก้ปัญหาสัตว์เดรัจฉานที่เห็นได้ชัด แต่ฉันตระหนักว่าเนื่องจาก OP ต้องการแก้ปัญหาด้วยตัวเลขหกหลักและตัวส่วนในเวลาไม่ถึงนาที ผมพบว่าสูตรที่มีประโยชน์ในหน้าวิกิพีเดียลำดับ Farey: ถ้า A / B, C / D เป็นเพื่อนบ้านในหนึ่งในลำดับ Farey ด้วยแล้วa/b<c/d b*c-a*b=1ขณะที่ลูปด้านใน f ในโปรแกรมของฉันขยายความจริงนี้ไปยังตัวเลขที่ไม่ลดลงโดยใช้ gcd ซึ่งอีกวงในขณะที่คำนวณ

ฉันเล่นกอล์ฟแล้วค่อนข้างยาก แต่ฉันชอบที่จะได้ยินคำแนะนำใด ๆ

การแก้ไข:

166-> 162: ลบaและออกbจากโปรแกรมภายนอก พวกเขาไม่จำเป็น
162-> 155: str()-> ``
155-> 154: เพิ่มkแล้ว
154-> 152: ลบออกxจากภายในฟังก์ชั่นผ่านมันเป็นอาร์กิวเมนต์แทน
152-> 150: ให้aค่าเริ่มต้นแทนที่จะส่งเป็นอาร์กิวเมนต์
150> 146: การเปลี่ยนแปลงการเริ่มต้นของและx 146-> 145: ถูกลบออก 145-> 144: เปลี่ยน ... และ ... หรือ ... เป็น (... , ... ) [... ] ดังนั้นจึงประหยัดพื้นที่ 144-> 138: เปลี่ยน (... , ... ) [... ] เป็น ... + ... * (... ) ขอบคุณ @ mbomb007y
k

กรณีทดสอบ:

2/5
1/3 1/2

1/2
0 1

2/4
1/3 2/3

179565/987657
170496/937775 128779/708320

12345678/87654321
12174209/86436891 11145405/79132382

การทดสอบครั้งที่สองถึงครั้งสุดท้ายใช้เวลาน้อยกว่าหนึ่งวินาทีบนคอมพิวเตอร์ของฉันในขณะที่การทดสอบล่าสุดใช้เวลาประมาณ 5-10 วินาที


นี่k=1คือความชั่วร้ายที่บริสุทธิ์
Evpok

1
@Evpok: ฉันพยายามทำให้ k = y = n ทำงาน แต่ดูเหมือนว่าถ้าคุณปรับเปลี่ยนตัวแปรภายในฟังก์ชั่นไพ ธ อนต้องการให้เป็นแบบโลคอล นี่เป็นวิธีเดียวในการรับตัวแปรโลคัลใน 4 อักขระ นอกจากนี้เนื่องจากเศษส่วนเป็นบวกและเหมาะสมตัวหารจะไม่สามารถเป็น 1 ได้
isaacg

อาร์กิวเมนต์บรรทัดคำสั่งเป็นเรื่องง่ายด้วย Python ดังนั้นจึงควรใช้สำหรับป้อนข้อมูลตามคำแนะนำที่นี่
Alex Thornton

1
" คุณสามารถเลือกได้ว่าคุณต้องการรับเศษส่วนเป็นอาร์กิวเมนต์บรรทัดคำสั่ง (เช่น yourprogram.exe 2/5) หรือแจ้งให้ป้อนข้อมูลผู้ใช้หรือไม่"
isaacg

บันทึก 6 ตัวอักษร:print`(a*n+p)/d`+('/'+`a`)*(a>1),
mbomb007

5

Mathematica, 163 ไบต์

{a,b}=FromDigits/@InputString[]~StringSplit~"/";r=Range[b-1];""<>Riffle[#~ToString~InputForm&/@(#@DeleteCases[#2[a/b*r]/r,a/b]&@@@{{Max,Floor},{Min,Ceiling}})," "]

สิ่งนี้ถูก จำกัด อย่างรุนแรงจากข้อกำหนดอินพุต / เอาต์พุตในฐานะอินพุตและสตริงของผู้ใช้ การจัดการกับสตริงนั้นยุ่งยากใน Mathematica (อย่างน้อยเมื่อคุณต้องการเล่นกอล์ฟ) การทำสิ่งนี้เป็นวิธีธรรมชาติใน Mathematica (โดยใช้เพียงจำนวนเต็มและปันส่วน) ฉันอาจทำให้ขนาดนี้ลดลงถึง 50%

สามารถทำตัวเลข 6 หลักในเครื่องของฉัน

อ่านได้ง่ายขึ้นเล็กน้อย (ไม่ใช่ที่ไม่ได้รับความนิยม):

{a, b} = FromDigits /@ InputString[]~StringSplit~"/";
r = Range[b - 1];
"" <> Riffle[#~ToString~
     InputForm & /@ (#[DeleteCases[#2[a/b*r]/r, a/b]] & @@@ {{Max, 
       Floor}, {Min, Ceiling}}), " "]

เพื่อความสนุกของมันการทำสิ่งนี้ด้วยวิธีที่เป็นธรรมชาติคือในฐานะที่เป็นฟังก์ชันที่ใช้ตัวเศษและส่วนและคืนค่าสองส่วนนี่เป็นเพียง84 ตัวอักษร (ดังนั้นการประมาณ 50% ของฉันจึงค่อนข้างใกล้เคียง):

f[a_,b_]:=#@DeleteCases[#2[a/b*(r=Range[b-1])]/r,a/b]&@@@{{Max,Floor},{Min,Ceiling}}

3

จูเลีย - 127 125 ไบต์

ฉันได้เข้าหาสิ่งนี้จากมุมมองทางคณิตศาสตร์เพื่อหลีกเลี่ยงความจำเป็นในการวนซ้ำดังนั้นโค้ดนี้ทำงานค่อนข้างเร็วสำหรับอินพุตขนาดใหญ่ (หมายเหตุ: ถ้า a / b เป็นอินพุตดังนั้น a * b ต้องพอดีภายใน Int64 (Int32 บนระบบ 32 บิต) มิฉะนั้นคำตอบที่ไร้สาระจะถูกสร้างขึ้น - ถ้า a และ b แสดงออกได้ใน Int32 (Int16 บนระบบ 32 บิต) จะไม่มีปัญหาเกิดขึ้น)

UPDATE: ไม่จำเป็นต้องใส่แบ็กสแลชโอเวอร์โหลดอีกต่อไปสำหรับ div อีกต่อไปโดยใช้÷ซึ่งเป็นการประหยัดสุทธิ 2 ไบต์

a,b=int(split(readline(),"/"));k=gcd(a,b);f=b-invmod(a÷k,b÷k);d=2b-f-b÷k;print(a*d÷b,d<2?" ":"/$d ",a*f÷b+1,"/$f"^(f>1))

Ungolfed:

a,b=int(split(readline(),"/")) # Read in STDIN in form a/b, convert to int
k=gcd(a,b)           # Get the greatest common denominator
f=b-invmod(a÷k,b÷k)  # Calculate the denominator of the next biggest fraction
d=2b-f-b÷k           # Calculate the denominator of the next smallest fraction
print(a*d÷b,d<2?" ":"/$d ",a*f÷b+1,"/$f"^(f>1)) # Calculate numerators and print

แนวคิดพื้นฐาน: ค้นหา d และ f ที่ใหญ่ที่สุดที่น้อยกว่า b ที่สอดคล้องกับ ad-bc = gcd (a, b) (ถัดไปน้อยที่สุด) และ be-af = gcd (a, b) (ใหญ่ที่สุดถัดไป) จากนั้นคำนวณ c และ e จาก ที่นั่น ผลลัพธ์ที่ได้คือ c / de / f ยกเว้น d หรือ f เป็น 1 ซึ่งในกรณีนี้จะไม่ใส่ / d หรือ / f

น่าสนใจซึ่งหมายความว่ารหัสนี้ยังใช้งานได้สำหรับเศษส่วนที่ไม่เหมาะสมในเชิงบวกตราบใดที่อินพุตไม่ใช่จำนวนเต็ม (นั่นคือ gcd (a, b) = a)

ในระบบของฉันการป้อน194857602/34512958303ข้อมูลไม่ต้องใช้เวลาในการรับรู้171085289/30302433084 23772313/4210525219


ทดสอบกับให้ฉัน55552/999999 -396/920632 486/936509
user2428118

@ user2428118 - คุณใช้ระบบ 32 บิต (หรือใช้ Julia 32 บิต)? ฉันใช้ "int" ซึ่งหมายความว่าในระบบ 32 บิตจะใช้ Int32 แทน Int64 จะช่วยให้int32(55552*999999) -282630400สำหรับฉันด้วยการทดสอบนั้นฉันได้รับ51143/920632 52025/936509- โปรดทราบว่าตัวส่วนเหมือนกันและนั่นคือ 52025-51143 = 486 - (- 396) ฉันจะเพิ่มบันทึกย่อเพื่อพูดถึงปัญหานี้
เกลน O

หากคุณต้องการให้แน่ใจว่ารหัสจะทำงานได้กับอินพุตขนาด Int64 ทั้งหมดคุณสามารถแทนที่ "int" ด้วย "int128" ด้วยการเปลี่ยนแปลงนั้นการป้อน1234567891234567/2145768375829475878ผลลัพธ์จะ869253326028691/1510825213275018197 365314565205876/634943162554457681เป็น การเปลี่ยนแปลงนี้เพิ่มเพียง 3 อักขระพิเศษ
เกลน O

ใช่ฉันใช้คอมพิวเตอร์ 32 บิต ฉันจะลองบนเครื่อง 64 บิตบางครั้งเมื่อฉันมีเวลา
2428118

การทดสอบบนคอมพิวเตอร์ 64 บิตให้ผลลัพธ์ที่ถูกต้องดังนั้นฉันจึงยอมรับคำตอบนี้
2428118

2

JavaScript, 131

ด้วยสัญลักษณ์ลูกศรไขมันและการevalโทร:

m=>{for(e=eval,n=e(m),i=p=0,q=1;++i</\d+$/.exec(m);)if(n*i>(f=n*i|0))g=f+1,p=f/i>e(p)?f+'/'+i:p,q=g/i<e(q)?g+'/'+i:q;return p+' '+q}

การ179565/987657ทดสอบความเครียดจะดำเนินการในประมาณ35 วินาทีบน Firefox และอีกมากมายบน Chrome (~ 6 นาที)

วิธีการเร็วขึ้นและไม่ใช้evalและสัญลักษณ์ลูกศรไขมัน

for(n=eval(m=prompt(a=i=p=0,b=c=d=q=1));++i<m.match(/\d+$/);)if(n*i>(f=n*i|0))g=f+1,p=f*c>i*a?(a=f)+'/'+(c=i):p,q=g*d<i*b?(b=g)+'/'+(d=i):q;alert(p+' '+q)

การ179565/987657ทดสอบความเครียดจะดำเนินการในประมาณ 5 วินาที

ไม่เล่นกอล์ฟ:

m=prompt(); //get input
a=0; c=1; //first fraction
b=1; d=1; //second fraction
n=eval(m); //evaluate input
for (i=1; i<m.match(/\d+$/); i++) { //loop from 1 to input denominator
  f=Math.floor(n*i);
  if (n*i > f) { //if fraction not equal to simplification of input
    g=f+1; // f/i and g/i are fractions closer to input
    if (f/i>a/c) a=f, c=i;
    if (g/i<b/d) b=g; d=i; 
  }
}
alert(a+'/'+c+' '+b+'/'+d); //output values handling 0 and 1 correctly

เกินไป ... มาก eval... EEK
John Dvorak

3
ทดสอบกับ2/6ให้1/3 2/5แต่1/3ไม่น้อยกว่าแต่เท่ากับ 2/6
user2428118

@ user2428118 คงที่
Michael M.

ทำไมคำตอบนี้จึงได้รับการยอมรับเร็ว
Evpok

1
@ user2428118: คุณรู้คุณสามารถให้เวลาสองสามวันก่อนที่จะยอมรับวิธีแก้ไขปัญหา นอกจากนี้วิธีนี้จะไม่สั้นที่สุดอีกต่อไป
isaacg

2

perl, 142 ไบต์ (155 โดยไม่มี CPAN)

use bare A..Z;$/="/";N=<>;D=<>;F=N/D;K=G=1;for$H(1..D){J<F&&J>E?(E,I):J>F&&J<G?(G,K):()=(J=$_/H,"$_/$H")for(Z=int F*H)..Z+1}print I||0," $K\n"

หรือหากโมดูล CPAN ไม่ได้รับอนุญาต / จำเป็นต้องใช้รหัสเร็วขึ้น 3-4 เท่า:

$/="/";$N=<>;$D=<>;$F=$N/$D;$g=$G=1;for$d(1..$D){$f<$F&&$f>$E?($E,$e):$f>$F&&$f<$G?($G,$g):()=($f=$_/$d,"$_/$d")for($z=int$F*$d)..$z+1}print$e||0," $g\n"

รุ่นก่อนใช้เวลา 9.55 วินาทีในเครื่องของฉันรุ่นหลัง 2.44 วินาที

อ่านไม่ได้น้อยลง:

($N, $D) = split(m[/], <>);
$F = $N / $D;
$G = 1;
foreach $d (1 .. $D) {
    $z = int $F * $d;
    foreach $_ ($z .. $z + 1) {
        $f = $_ / $d;
        ($f < $F && $f > $E ? ($E, $e) :
        ($f > $F && $f < $G ? ($G, $g) : ())) = ($f, "$_/$d");
    }
}
print $e || 0, ' ', $g || 1, "\n";
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.