1. 程式人生 > >[51nod1187][類歐幾里得演算法]尋找分數

[51nod1187][類歐幾里得演算法]尋找分數

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的演算法 不妨設函式F(a,b,c,d)F(a,b,c,d)表示該狀態下的答案 當a=0a=0,顯然只需滿足PQ&lt;CD\frac{P}{Q}&lt;\frac{C}{D}P=1P=1時有最優解Q=DCQ=\frac{D}{C}a&gt;=ba&gt;=b,前面是一個假分數,我們化為真分數的形式進入轉移F(a%b,b,cd(ab),d)F(a\%b,b,c-d*(\frac{a}{b}),d)

a),d),最後加上 當c&gt;dc&gt;d,此時不滿足前兩個條件,顯然有ab&lt;1\frac{a}{b}&lt;1,返回P=Q=1P=Q=1 三個條件沒有任意一個滿足時,原式為ab&lt;pq&lt;cd\frac{a}{b}&lt;\frac{p}{q}&lt;\frac{c}{d} 取倒數,轉為dc&lt;qp&lt;ba\frac{d}{c}&lt;\frac{q}{p}&lt;\frac{b}{a},進入轉移F(d,c,b,a)F(d,c,b,a),返回時將P,QP,Q交換 觀察到每次對另一個數取模及交換,稱為類歐幾里得演算法

#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;
}