hdu_4180 RealPhobia (扩展欧几里德)

来源:互联网 发布:游戏宣传片制作软件 编辑:程序博客网 时间:2024/05/29 17:38

http://acm.hdu.edu.cn/showproblem.php?pid=4180

题意:

给一个真分数A/B,求C/D,D<B并且fabs(A/B-C/D)最小(即两个分数距离最近)
思路:
要求|a/b-c/d|最小,先通分得|(a*d-b*c)/(b*a)|,使其最小,分母为最小莫过于为1,(为0的话表示可以约分,直接输出约分后的分数)。
分母尽可能大。
a*d-b*c=1或者b*c-a*d=1...#
由扩展欧几里德
a*x+b*y=gcd(a,b);
所以 d=x,c=-y 或者 c=y,d=-x
由#式可得a(d+b)-b(c+a)=1或者b(c+a)-a(d+b)=1 
可解得 d=x+b,c=-y+a 或者 c=y+a,d=-x+b; //这里要取模,目的是把分子分母变成正数 
最后输出分母大的一组。(因为b*a会更大)

PS:这题DT了好久,暴力超时,搜索连分数也不好做。。。 

我的代码:

/*program:hdu4180,hnu12445author:BlackAndWhite*/ #include<stdio.h>__int64 T,a,b;__int64 x,y,gcd,c1,d1,c2,d2;__int64 extended_gcd(__int64 a,__int64 b,__int64 &x,__int64 &y){    __int64 ans,t;    if (b==0) { x=1; y=0; return a; }    else { ans=extended_gcd(b,a%b,x,y); t=x; x=y; y=t-(a/b)*y;}    return ans;}int main(){    scanf("%I64d",&T);    while(T--)    {        scanf("%I64d/%I64d",&a,&b);        gcd=extended_gcd(a,b,x,y);        if(gcd!=1){printf("%I64d/%I64d\n",a/gcd,b/gcd);continue;}        if(a==1){printf("1/%I64d\n",b-1);continue;}        d1=(x+b)%b;        c1=(-y+a)%a;        c2=(y+a)%a;        d2=(-x+b)%b;        if(d1<d2) printf("%I64d/%I64d\n",c2,d2);        else printf("%I64d/%I64d\n",c1,d1);    }    return 0;}