[Solver] SPOJ FINFRAC

Source: Internet
Author: User
Tags integer division

Address: http://www.spoj.com/problems/FINFRAC/

Question:

Give four integers a, B, c, d, and look for two integers p, q, so that a/B <p/q <c/d, q is the smallest, if multiple solutions exist, finding p is the smallest.

Solution 1 (not strictly proven ):

There is a sequence called a mine sequence. The magic of a mine sequence is that if a/B <c/d, a/B <(a + c)/(B + d) <c/d, then there is a/B <(2a + c)/(2b + d) <(a + c)/(B + d) <(a + 2c) /(B + 2d) <c/d

We found that the more the score "Participate", the closer the result is to the previous score, and vice versa.

Inspired by this, set two weights x> 0 and y> 0 (if they are equal to 0, they cannot be strictly greater than or less than), with a/B <(xa + yc) /(xb + yd) <c/d

It can be proved that (xa + yc)/(xb + yd) can cover all the scores between a/B and c/d, so the p/q we require must be in this form.

The meaning requires that p and q be the smallest, so the gcd of (xa + yc) and (xb + yd) should be as big as possible, and then divide the gcd into smaller denominator.

The problem is converted to gcd (xa + yc, xb + yd), where abcd is known, x and y are for it, and gcd (ax + cy, bx + dy) is another method ), here, we can use Euclidean to perform division. For example.

A = 7, B = 5, c = 8, d = 5, then gcd (7x + 8y, 5x + 5y) = gcd (2x + 3y, 5x + 5y) = gcd (2x + 3y, 3x + 2y), so we can't continue. Because one side x is more than one side y, then we assume they are equal,

That is, 2x + 3y = 3x + 2y, and x = y. The formula is as follows: (7x + 8y)/(5x + 5y) = 15x/10x = 3/2.

The Code is as follows:

#include <stdio.h>#define LL long long#define ABS(x) ( (x) < 0 ? -(x) : (x) )LL  gcd( LL a, LL b ) {        while( b > 0 ) {                LL  t = a % b;                a = b;                b = t;        }        return a;}void  solve( int a, int b, int c, int d, int& x, int& y ) {        x = y = 1;        int  t1, t2;        while(1) {                t1 = t2 = 0x7fffffff;                if( a >= b && c >= d ) {                        if( b > 0 ) t1 = a / b;                        if( d > 0 ) t2 = c / d;                        if( t1 > t2 ) t1 = t2;                        a -= t1 * b;                        c -= t1 * d;                }                else if( a <= b && c <= d ) {                        t1 = a; a = b; b = t1;                        t2 = c; c = d; d = t2;                }                else break;        }        x = ABS( c - d );        y = ABS( a - b );        if( x == 0 ) x = 1;        if( y == 0 ) y = 1;}int main() {        int  a, b, c, d, x, y, tmp;        LL   p, q, tmp2;        while( scanf( "%d%d%d%d", &a, &b, &c, &d ) == 4 ) {                tmp = gcd( a, b ); a /= tmp; b /= tmp;                tmp = gcd( c, d ); c /= tmp; d /= tmp;                solve( a, b, c, d, x, y );                p = a * (LL)x + c * (LL)y;                q = b * (LL)x + d * (LL)y;                tmp2 = gcd( p, q );                printf( "%lld/%lld\n", p / tmp2, q / tmp2 );        }        return 0;}

Solution 2 (read the online answer ):

If [a/B] is set, a/B is rounded down.

2.1 If a/B> = 1 and k = [a/B], you can know (a/B)-k <(p/q) -k <(c/d)-k, that is, (a-bk)/B <(p-qk)/q <(c-dk)/d, set a' = a-bk, p' = p-qk, C' = c-dk, after the solution of A'/B <P'/q <C'/d is obtained, p = P' + qk can obtain the true p and q. If you know a, B, q, p has another method (that is, you do not need to obtain p from recursion), that is, p = q * a/B.
+ 1 (if it is regarded as an integer), this is because p> q * a/B (if it is regarded as a floating point number), while the integer division will discard the remainder, so it just adds 1.

2.2 If a/B <1

2.2.1 If c/d> 1, p = q = 1

2.2.2 If c/d <= 1, the problem can be converted to d/c <q/p <B/

The Code is as follows:

#include <stdio.h>#define LL long longLL  findq( LL a, LL b, LL c, LL d ) {        if( a < b ) {                if( c > d ) return 1;                else  return  findq( d, c, b, a ) * d / c + 1;        }        else {                LL  k = a / b;                return  findq( a - k * b, b, c - k * d, d );        }}int main() {        LL  a, b, c, d, p, q;        while( scanf( "%lld%lld%lld%lld", &a, &b, &c, &d ) == 4 ) {                q = findq( a, b, c, d );                p = q * a / b + 1;                printf( "%lld/%lld\n", p, q );        }        return 0;}

References:

Http://apps.topcoder.com/forums/;jsessionid=627E3C18A18ED2AA6A5B4BDB4F1A0C3D? Module = RevisionHistory & amp; messageID = 1204829

Wxcc code: http://acm.hust.edu.cn/vjudge/contest/viewSource.action? Id = 192084


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.