洛谷 P2118 比例简化
JDOJ 2892: [NOIP2014]比例简化 T2
Description
在社交媒体上,经常会看到针对某一个观点同意与否的民意调查以及结果。例如,对某一观点表示支持的有 1498人,反对的有 902人,那么赞同与反对的比例可以简单的记为 1498:902。
不过,如果把调查结果就以这种方式呈现出来,大多数人肯定不会满意。因为这个比例的数值太大,难以一眼看出它们的关系。对于上面这个例子,如果把比例记为 5:3,虽然与真实结果有一定的误差,但依然能够较为准确地反映调查结果,同时也显得比较直观。
现给出支持人数 A,反对人数 B,以及一个上限 L,请你将 A比 B化简为 A'比 B',要求在 A'和 B'均不大于 L且 A'和 B'互质(两个整数的最大公约数是 1)的前提下, A'/B' ≥ A/B且 A'/B'-A/B的值尽可能小。
Input
输入共一行,包含三个整数 A,B,L,每两个整数之间用一个空格隔开,分别表示支持人数、反对人数以及上限。
Output
输出共一行,包含两个整数 A',B',中间用一个空格隔开,表示化简后的比例。
Sample Input
1498 902 10
Sample Output
5 3
HINT
【数据说明】
对于 100%的数据,1 ≤ A ≤ 1,000,000,1 ≤ B ≤ 1,000,000,1 ≤ L ≤ 100, A/B ≤ L。
题解:
这是一道数学题。我认为这道题运用了一个“逼近”的思想,我需要在可能的情况下将我的所有合法解无限地向差值尽可能小的情况逼近。
所以我们来看一下数学上的推导过程。
A'/B' >= A/B,根据十字相乘法可以把除法运算变成整数乘法,在int中解决问题,
即:
A' * B >= B'*A
由于数据比较小,我们想到暴力枚举。最后把ans1(a')ans2(b')的初值设置一下。开始跑两层循环,判断我们手写gcd函数,下一步便是难以考虑的:逼近。
我们要维护最小差值,也就是一直更新ans1,ans2,那么我们怎么判断什么时候更新ans1,ans2呢?
判断条件:
A'1/B'1 > A'2/B'2
即:
A'1 *B'2 > A'2 * B'1
PS:GCD函数的辗转相除是非常常用的数学手写函数,需要熟练掌握背下来
这样操作过程就被完善了,上AC代码:
#include<cstdio>
using namespace std;
int a,b,ans1,ans2,l;
int gcd(int x,int y)
{
if(y==0)
return x;
return gcd(y,x%y);
}
int main()
{
scanf("%d%d%d",&a,&b,&l);
ans1=l;ans2=1;
for(int i=1;i<=l;i++)
for(int j=1;j<=l;j++)
if(gcd(i,j)==1 && i*b>=j*a && i*ans2<j*ans1)
ans1=i,ans2=j;
printf("%d %d",ans1,ans2);
return 0;
}