가장 가까운 분수


24

태스크:

귀하의 프로그램은 형식에 따라 적절 하고 긍정적 인 간단한 분수<numerator>/<denominator>받습니다.

이 입력의 경우 두 개의 분수를 찾아야합니다.

  1. 입력 값보다 작은 분수입니다.
  2. 입력 값보다 큰 분수입니다.

두 분수 모두 입력 값보다 분모가 낮아야합니다. 가능한 모든 분수 중에서 입력과 가장 낮은 차이를 가져야합니다.

산출:

프로그램의 출력은 다음과 같아야합니다.

  • 형식에서 입력보다 작은 분수입니다 <numerator>/<denominator>.
  • 뒤에 공백 문자 (ASCII 코드 32)가옵니다.
  • 형식에서 입력보다 큰 분수가 뒤에옵니다 <numerator>/<denominator>.

다음과 같이

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

규칙 :

  • 출력 된 모든 분수 는 가장 낮은 용어 이어야합니다 .
  • 출력 된 모든 분수는 적절한 분수 여야합니다.
  • 규칙에 의해 허용되는 적절한 분수가없는 경우 0분수 <입력 1대신 분수> 입력 대신 출력해야합니다 .
  • 분수를 명령 줄 인수 (예 :)로 yourprogram.exe 2/5받거나 사용자 입력 프롬프트 로 받을지 여부를 선택할 수 있습니다 .
  • 프로그램이 유효하지 않은 입력을받지 못한다고 가정 할 수 있습니다.
  • 가장 짧은 코드 (모든 언어로 된 바이트)가 이깁니다.
  • 비표준 명령 줄 인수 (일반적으로 스크립트를 실행하는 데 필요하지 않은 인수)는 총 문자 수에 포함됩니다.

  • 프로그램 이하지 말아야 할 것 :

    • 외부 자원에 의존하십시오.
    • 특정 파일 이름이 있어야합니다.
    • 필요한 출력 이외의 것을 출력하십시오.
    • 실행하는 데 시간이 오래 걸립니다. 179565/987657일반 가정 사용자의 컴퓨터에서 6 자리 분자와 분모가있는 분수 (분수)에 대해 프로그램이 1 분 이상 실행되면 유효하지 않습니다.
    • 0분모가있는 분수를 출력 합니다. 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
첫 번째 예는 output 1/3 1/2입니다.
Heiko Oberdiek

@HeikoOberdiek 당신이 맞아요. 결정된.
user2428118

1
"평균적인 사용자 컴퓨터"를 정의하십시오. 1.6GHz Intel Atom 시스템에서 90 초가 허용됩니까?
John Dvorak

2
마지막 예가 잘못되었습니다. 입력 분수는 출력 분수의 첫 번째 분수와 같습니다.
DavidC

답변:


3

세이지 - 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

세이지는 마지막 줄에서만 필요하며 출력을 처리합니다. 다른 모든 것은 파이썬에서도 작동합니다.

교체 raw_input()sys.argv[1]입력 대신 프롬프트의 명령 줄 인수에서 읽고 있습니다. 문자 수는 변경되지 않습니다. ( sys먼저 가져 오기 없이는 Python에서 작동하지 않습니다 .)

이는 본질적으로 기존 요소의 중간 값을 사용하여 각 Farey 시퀀스 를 재귀 적으로 구성 하지만 입력에 가장 가까운 요소로 제한됩니다. 다른 관점에서, 각 Farey 시퀀스에 대해 중첩 간격 검색을 실행합니다.

내 컴퓨터에서 1 초 이내에 모든 예제를 올바르게 처리합니다.

ungolfed 버전은 다음과 같습니다.

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

파이썬 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가 1 분 안에 6 자리 분자와 분모가있는 인스턴스를 풀고 싶었 기 때문에 1 조의 가능성을 시도하는 것보다 더 나은 솔루션이 필요하다는 것을 깨달았습니다. I는 페리 수열에 대한 위키 페이지에 유용한 화학식 발견 : A / B, C / D가 더불어 Farey 서열 중 하나에 인접하는 경우 a/b<c/d, 다음 b*c-a*b=1. 내 프로그램에서 f 내부의 while 루프는 gcd를 사용 하여이 사실을 축소되지 않은 숫자로 확장합니다. 다른 cd는 계산합니다.

나는 이것을 꽤 열심히 골랐다. 그러나 나는 어떤 제안이라도 듣고 싶다.

편집 :

166-> 162 : 제거 ab외부 프로그램. 그들은 불필요했습니다.
162-> 155 : str()->``
155-> 154 : 추가됨 k.
154-> 152 : x함수 내부에서 제거 되어 대신 인수로 전달되었습니다.
152-> 150 : a인수로 전달하는 대신 기본값을 제공했습니다.
150-> 146 : x및 의 초기화가 변경되었습니다 y.
146-> 145 : 제거됨 k.
145-> 144 : ... 및 ... 또는 ...을 (..., ...) [...]으로 변경하여 공간을 절약했습니다.
144-> 138 : (..., ...) [...]가 ... + ... * (...)로 변경되었습니다. @ mbomb007에게 감사합니다.

테스트 사례 :

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

마지막 테스트는 내 컴퓨터에서 1 초 미만이 걸리고 마지막 테스트는 5-10 초가 걸렸습니다.


이것은 k=1순수한 악입니다.
Evpok

1
@Evpok : k = y = n을 작동 시키려고했지만 함수 내부에서 변수를 수정하면 파이썬은 변수를 로컬로 만들고 싶습니다. 이것은 4 문자로 지역 변수를 얻는 유일한 방법이었습니다. 또한 분수가 양수이고 적절하기 때문에 분모는 1이 될 수 없습니다.
isaacg

파이썬에서는 명령 줄 인수가 쉬우므로 여기에 지시 된대로 입력에 사용해야했습니다.
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 (32 비트 시스템의 Int32)에 맞아야합니다) 그렇지 않으면 넌센스 응답이 생성됩니다. a와 b가 모두 Int32 (32 비트 시스템의 Int16)로 표현 가능하면 문제가 발생하지 않습니다).

업데이트 : 더 이상 2 바이트를 절약하는 ÷를 사용하여 div에 대한 백 슬래시를 더 이상 과부하 할 필요가 없습니다.

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

언 골프 드 :

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

기본 아이디어 : ad-bc = gcd (a, b) (다음으로 가장 작음) 및 be-af = gcd (a, b) (다음으로 가장 높음)을 만족하는 b보다 큰 d와 f를 찾은 다음 c와 e를 계산합니다. 그곳에. d 또는 f가 1이 아닌 경우 결과 출력은 c / de / f입니다.이 경우 / d 또는 / f는 생략됩니다.

흥미롭게도 이것은 입력이 정수가 아닌 한 (즉, gcd (a, b) = a) 코드가 양의 부적절한 분수에 대해서도 작동한다는 것을 의미합니다.

내 시스템에서 입력하는 194857602/34512958303데 인식하는 데 시간이 걸리지 않습니다.171085289/30302433084 23772313/4210525219


테스트 55552/999999는 저에게 제공합니다 -396/920632 486/936509.
user2428118

@ user2428118-32 비트 시스템 (또는 32 비트 Julia)을 사용하고 있습니까? "int"를 사용했습니다. 즉, 32 비트 시스템에서는 Int64 대신 Int32를 사용합니다. int32(55552*999999)제공합니다 -282630400. 나에게 그 테스트 51143/920632 52025/936509를 통해 분모가 같고 52025-51143 = 486-(-396)이라는 것을 알 수 있습니다. 이 문제에 대한 메모를 추가하겠습니다.
Glen O

코드가 모든 Int64 크기 입력에 대해 작동하도록하려면 "int"를 "int128"로 바꿀 수 있습니다. 그 변화로, 입력 1234567891234567/2145768375829475878결과는 869253326028691/1510825213275018197 365314565205876/634943162554457681. 이 변경으로 3 개의 문자 만 추가됩니다.
Glen O

예, 32 비트 컴퓨터를 사용하고 있습니다. 시간이 있으면 언젠가 64 비트 컴퓨터에서 시도해 보겠다.
user2428118

64 비트 컴퓨터에서 테스트하면 올바른 결과를 얻을 수 있으므로이 답변에 동의합니다.
user2428118 2016 년

2

자바 스크립트, 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초 , 파이어 폭스에 더 많은 크롬에 (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 fixed
Michael M.

이 답변이 왜 그렇게 일찍 받아 들여졌습니까?
Evpok

1
@ user2428118 : 솔루션을 수락하기 전에 며칠이 걸릴 수 있습니다. 또한이 솔루션은 더 이상 가장 짧지 않습니다.
isaacg

2

perl, 142 바이트 (CPAN이없는 155)

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.