Phần gần nhất


24

Bài tập:

Chương trình của bạn được cho một thích hợp , tích cực phần đơn giản trong định dạng <numerator>/<denominator>.

Đối với đầu vào này, nó phải tìm hai phân số.

  1. Một phần nhỏ hơn đầu vào.
  2. Một phần lớn hơn đầu vào.

Cả hai phân số phải có mẫu số thấp hơn đầu vào. Trong tất cả các phân số có thể, chúng nên có mức chênh lệch thấp nhất so với đầu vào.

Đầu ra:

Đầu ra của chương trình của bạn phải là:

  • Một phần nhỏ hơn đầu vào, trong định dạng <numerator>/<denominator>.
  • Tiếp theo là một ký tự khoảng trắng (ASCII - mã 32).
  • Tiếp theo là một phân số lớn hơn đầu vào, trong định dạng <numerator>/<denominator>.

Như sau:

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

Quy tắc:

  • Tất cả các phân số xuất ra phải ở mức thấp nhất .
  • Tất cả các phân số xuất ra phải là phân số thích hợp.
  • Nếu không có phân số thích hợp nào có thể được các quy tắc cho phép, bạn phải xuất ra 0thay vì phân số <đầu vào và 1thay vì phân số> đầu vào.
  • Bạn có thể chọn xem bạn muốn nhận phân số dưới dạng đối số dòng lệnh (ví dụ yourprogram.exe 2/5) hoặc lời nhắc cho đầu vào của người dùng.
  • Bạn có thể cho rằng chương trình của bạn sẽ không nhận được đầu vào không hợp lệ.
  • Mã ngắn nhất (tính bằng byte, bằng bất kỳ ngôn ngữ nào) sẽ thắng.
  • Bất kỳ đối số dòng lệnh không chuẩn nào (đối số thường không được yêu cầu để chạy tập lệnh) đều được tính vào tổng số ký tự.

  • Những gì chương trình của bạn không được làm:

    • Phụ thuộc vào bất kỳ nguồn lực bên ngoài.
    • Phụ thuộc vào việc có một tên tập tin cụ thể.
    • Đầu ra bất cứ điều gì khác ngoài đầu ra cần thiết.
    • Mất nhiều thời gian để chạy. Nếu chương trình của bạn chạy hơn một phút đối với các phân số có tử số và mẫu số 6 chữ số (ví dụ 179565/987657) trên máy tính của người dùng gia đình trung bình, điều đó không hợp lệ.
    • Phân số đầu ra với 0mẫu số. Bạn không thể chia cho số không.
    • Phân số đầu ra với 0tử số. Chương trình của bạn phải xuất ra 0thay vì một phần nhỏ.
    • Giảm một phần đầu vào. Nếu phân số được đưa ra làm đầu vào có thể rút gọn, bạn phải sử dụng phân số khi được nhập.
  • Chương trình của bạn không được viết bằng ngôn ngữ lập trình mà không tồn tại trình biên dịch / trình thông dịch có sẵn công khai trước khi thử thách này được đăng.

Ví dụ:

Đầu vào: 2/5
Đầu ra: 1/3 1/2

Đầu vào: 1/2
Đầu ra: 0 1

Đầu vào: 5/9
Đầu ra: 1/2 4/7

Đầu vào: 1/3
Đầu ra: 0 1/2

Đầu vào: 2/4
Đầu ra: 1/3 2/3

Đầu vào: 179565/987657
Đầu ra: 170496/937775 128779/708320


1
Ví dụ đầu tiên của bạn không khớp với đặc điểm kỹ thuật: Cả hai phân số phải có mẫu số thấp hơn đầu vào.
Howard

1
Ví dụ đầu tiên, đầu ra nên được 1/3 1/2.
Heiko Oberdiek

@HeikoOberdiek Bạn nói đúng. Đã sửa.
dùng2428118

1
Xác định "máy tính gia đình trung bình". 90 giây trên máy Intel Atom 1.6GHz có được chấp nhận không?
John Dvorak

2
Ví dụ cuối cùng của bạn là không chính xác. Phân số đầu vào bằng với phân số đầu tiên của phân số đầu ra.
DavidC

Câu trả lời:


3

Hiền nhân - 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 chỉ cần thiết trong dòng cuối cùng, trong đó chăm sóc đầu ra. Mọi thứ khác cũng hoạt động trong Python.

Thay thế raw_input()bằng sys.argv[1]để đọc đầu vào từ một đối số dòng lệnh thay vì lời nhắc. Điều này không thay đổi số lượng nhân vật. (Không hoạt động trong Python mà không nhập systrước.)

Điều này về cơ bản xây dựng đệ quy trình tự Farey tương ứng bằng cách sử dụng các phương tiện truyền thông của các phần tử hiện có, nhưng giới hạn chính nó với các phần tử gần nhất với đầu vào. Từ quan điểm khác, nó chạy một tìm kiếm khoảng thời gian lồng nhau trên các chuỗi Farey tương ứng.

Nó xử lý chính xác tất cả các ví dụ trong chưa đầy một giây trên máy của tôi.

Đây là một phiên bản chưa được chỉnh sửa:

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

Tôi đã sợ rằng tôi sẽ không nhận được bất kỳ đệ trình mới nào cho tiền thưởng này. Công việc tuyệt vời
dùng2428118

Thủ thuật hay với exec!
xnor

Là câu trả lời duy nhất được gửi trong thời gian tiền thưởng, tôi sẽ trao thưởng cho bạn tiền thưởng. Xin chúc mừng.
dùng2428118

Tôi chỉ sửa một lỗi trong một ví dụ. Bạn có thể muốn sửa bài nộp của mình (mặc dù đã nửa năm kể từ khi bạn gửi bài).
user2428118

12

Con trăn 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)

Tôi đã bắt đầu với giải pháp vũ phu rõ ràng, nhưng tôi nhận ra rằng vì OP muốn có thể giải quyết các trường hợp với tử số và mẫu số sáu chữ số trong một phút, tôi cần một giải pháp tốt hơn là thử một nghìn tỷ khả năng. Tôi đã tìm thấy một công thức hữu ích trên trang Wikipedia cho chuỗi Farey: Nếu a / b, c / d là hàng xóm trong một trong các chuỗi Farey a/b<c/d, sau đó, với b*c-a*b=1. Vòng lặp while bên trong f trong chương trình của tôi mở rộng thực tế này thành các số không giảm, sử dụng gcd, vòng lặp kia tính toán.

Tôi đã chơi golf khá khó khăn rồi, nhưng tôi rất thích nghe bất kỳ lời đề nghị nào.

Chỉnh sửa:

166-> 162: Đã xóa abkhỏi chương trình bên ngoài. Chúng không cần thiết.
162-> 155: str()-> ``
155-> 154: Đã thêm k.
154-> 152: xThay vào đó, loại bỏ từ bên trong hàm, thay vào đó là đối số.
152-> 150: Đưa ra amột giá trị mặc định thay vì chuyển nó làm đối số.
150-> 146: Thay đổi khởi tạo xy.
146-> 145: Đã xóa k.
145-> 144: Đã thay đổi ... và ... hoặc ... thành (..., ...) [...], do đó tiết kiệm một khoảng trống.
144-> 138: Đã thay đổi (..., ...) [...] thành ... + ... * (...). Cảm ơn @ mbomb007.

Các trường hợp thử nghiệm:

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

Thử nghiệm thứ hai đến lần cuối mất dưới một giây trên máy tính của tôi, trong khi thử nghiệm cuối cùng mất khoảng 5-10 giây.


Đây k=1là sự gian ác trong sạch.
Evpok

1
@Evpok: Tôi đã cố gắng để k = y = n hoạt động, nhưng rõ ràng nếu bạn sửa đổi một biến trong hàm, python muốn nó là cục bộ. Đây là cách duy nhất để có được một biến cục bộ trong 4 ký tự. Ngoài ra, vì phân số là dương và đúng, mẫu số không thể là 1.
isaacg

Đối số dòng lệnh dễ dàng với Python, vì vậy chúng nên được sử dụng cho đầu vào như được hướng dẫn ở đây.
Alex Thornton

1
" Bạn có thể chọn xem bạn muốn nhận phân số dưới dạng đối số dòng lệnh (ví dụ: yourprogram.exe 2/5) hoặc lời nhắc cho đầu vào của người dùng ."
isaacg

Lưu 6 ký tự:print`(a*n+p)/d`+('/'+`a`)*(a>1),
mbomb007

5

Toán học, 163 byte

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

Điều này bị hạn chế nghiêm trọng bởi yêu cầu đầu vào / đầu ra là đầu vào và chuỗi của người dùng. Đối phó với các chuỗi thực sự cồng kềnh trong Mathematica (ít nhất là khi bạn muốn chơi gôn). Thực hiện điều này theo cách tự nhiên trong Mathicala, (chỉ sử dụng số nguyên và số hữu tỷ) tôi có thể nhận được điều này xuống tới 50% kích thước.

Nó có thể thực hiện các số có 6 chữ số trong vài giây trên máy của tôi.

Hơi dễ đọc hơn (mặc dù không thực sự vô dụng):

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

Để giải trí, thực hiện "cách tự nhiên" này, tức là một hàm lấy tử số và mẫu số và trả về hai số hữu tỷ, đây chỉ là 84 ký tự (vì vậy ước tính 50% của tôi thực sự khá gần):

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

3

Julia - 127 125 byte

Tôi đã tiếp cận điều này từ góc độ toán học để tránh sự cần thiết của các vòng lặp, vì vậy mã này chạy khá nhanh đối với các đầu vào lớn (lưu ý: nếu a / b là đầu vào, thì a * b phải nằm trong Int64 (Int32 trên các hệ thống 32 bit) , nếu không, các câu trả lời vô nghĩa được tạo ra - nếu cả a và b đều có thể biểu thị được trong Int32 (Int16 trên hệ thống 32 bit), không có vấn đề gì xảy ra).

CẬP NHẬT: Không còn cần phải quá tải dấu gạch chéo ngược cho div, bằng cách sử dụng, một mạng tiết kiệm 2 byte.

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

Ung dung:

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

Ý tưởng cơ bản: tìm d lớn nhất và d nhỏ hơn b thỏa mãn ad-bc = gcd (a, b) (nhỏ nhất tiếp theo) và be-af = gcd (a, b) (lớn nhất tiếp theo), sau đó tính c và e từ ở đó Kết quả đầu ra là c / de / f, trừ khi d hoặc f là 1, trong trường hợp đó / d hoặc / f bị bỏ qua.

Thật thú vị, điều này có nghĩa là mã cũng hoạt động cho các phân số dương không chính xác, miễn là đầu vào không phải là số nguyên (nghĩa là gcd (a, b) = a).

Trên hệ thống của tôi, việc nhập 194857602/34512958303không mất thời gian có thể nhận biết để xuất171085289/30302433084 23772313/4210525219


Kiểm tra với 55552/999999cho tôi -396/920632 486/936509.
dùng2428118

@ user2428118 - Bạn có đang sử dụng hệ thống 32 bit (hoặc sử dụng Julia 32 bit) không? Tôi đã sử dụng "int", có nghĩa là trên hệ thống 32 bit, nó sẽ sử dụng Int32 thay vì Int64. int32(55552*999999)cho -282630400. Đối với tôi, với bài kiểm tra đó, tôi nhận được 51143/920632 52025/936509- lưu ý rằng mẫu số là như nhau và 52025-51143 = 486 - (- 396). Tôi sẽ thêm một lưu ý để đề cập đến vấn đề này.
Glen O

Nếu bạn muốn đảm bảo rằng mã sẽ hoạt động cho tất cả các đầu vào kích thước Int64, bạn có thể thay thế "int" bằng "int128". Với sự thay đổi đó, nhập 1234567891234567/2145768375829475878kết quả vào 869253326028691/1510825213275018197 365314565205876/634943162554457681. Thay đổi này chỉ thêm 3 ký tự.
Glen O

Có, tôi đang sử dụng máy tính 32 bit. Thỉnh thoảng tôi sẽ thử nó trên máy 64 bit khi tôi có thời gian cho nó.
dùng2428118

Thử nghiệm trên máy tính 64 bit cho kết quả chính xác, vì vậy tôi chấp nhận câu trả lời này.
dùng2428118

2

JavaScript, 131

Với ký hiệu mũi tên béo và evalcác cuộc gọi:

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}

Bài 179565/987657kiểm tra căng thẳng được thực hiện trong khoảng 35 giây trên Firefox, nhiều hơn nữa trên Chrome (~ 6 phút)

Phương pháp nhanh hơn và không có evalvà ký hiệu mũi tên béo

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)

Bài 179565/987657kiểm tra căng thẳng được thực hiện trong khoảng 5 giây.

Không chơi gôn:

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

quá ... nhiều ... eval. TUẦN
John Dvorak

3
Thử nghiệm với 2/6cho 1/3 2/5, tuy nhiên 1/3không ít hơn nhưng bằng 2/6 .
dùng2428118

@ user2428118 đã được sửa
Michael M.

Tại sao câu trả lời này được chấp nhận sớm như vậy?
Evpok

1
@ user2428118: Bạn biết đấy, bạn có thể cho phép một vài ngày trôi qua trước khi chấp nhận giải pháp. Ngoài ra, giải pháp này không còn là ngắn nhất.
isaacg

2

perl, 142 byte (155 không có 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"

Hoặc nếu các mô-đun CPAN không được phép / cần mã nhanh hơn 3-4 lần:

$/="/";$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"

Phiên bản cũ mất 9,55 giây trên máy của tôi, phiên bản sau 2,44 giây.

Ít đọc hơn:

($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";
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.