[51nod1187][類歐幾里得演算法]尋找分數
阿新 • • 發佈:2018-12-16
Description
給出 a,b,c,d, 找一個分數p/q,使得a/b < p/q < c/d,並且q最小。例如:1/3同1/2之間,符合條件且分母最小的分數是2/5。(如果q相同,輸出p最小的)
Input
第1行:一個數T,表示後面用作輸入測試的數的數量。(1 <= T <= 10000) 第2 - T + 1行:每行4個數,a,b,c,d,中間用空格分隔。(1 <= a,b,c,d <= 10^9)
Output
輸出共T行,對應符合條件的分數。
Sample Input
4 1 3 1 2 2 1 3 1 2 1 4 1
1000 1001 1001 1002
Sample Output
2/5 5/2 3/1 2001/2003
題解
這是一個類似gcd的演算法 不妨設函式表示該狀態下的答案 當,顯然只需滿足,時有最優解 當,前面是一個假分數,我們化為真分數的形式進入轉移,最後加上 當,此時不滿足前兩個條件,顯然有,返回 三個條件沒有任意一個滿足時,原式為 取倒數,轉為,進入轉移,返回時將交換 觀察到每次對另一個數取模及交換,稱為類歐幾里得演算法
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void write(LL x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
inline void pr1(int x){write(x);printf("/");}
inline void pr2(LL x){write(x);puts("");}
LL a,b,c,d;
struct ph
{
LL p,q;
ph(){}
ph(LL _p,LL _q){p=_p;q=_q;}
};
ph likegcd(LL a,LL b,LL c,LL d)
{
if(a==0)return ph(1,d*1.0/c*1.0+1);
else if(a>=b)
{
ph tmp=likegcd(a%b,b,c-d*(a/b),d);
return ph(tmp.p+tmp.q*(a/b),tmp.q);
}
else if(c>d)return ph(1,1);
else
{
ph tmp=likegcd(d,c,b,a);
return ph(tmp.q,tmp.p);
}
}
int main()
{
int T=read();while(T--)
{
a=read();b=read();c=read();d=read();
ph re=likegcd(a,b,c,d);
pr1(re.p);pr2(re.q);
}
return 0;
}