参考: http://www.jianshu.com/p/5303f2431f05
原题: https://www.patest.cn/contests/pat-b-practise/1034
思路: 本题其实不难, 关键是测试点刁钻. 改了老半天, 在
网上找了很多资料, 最终才AC
测试点2: 测试和0相关的输入
测试点3: 测试结果为负负的情况
本题, 在PAT服务器上进行提交测试, 发现使用相减法求最大公约数不能AC,
原因不明, 而使用辗转相除法可以AC, 下面的实现, 可以做到不需要求带负
数的最大公约数问题, 但是带0求最大公约数不可避免.
题目虽然说, 各种计算不超过int
, 但是为了方便, 比如计算乘法, 无需先通分
而是直接乘, 所以尽量使用long
.
实现:
#include <stdio.h>
long getgcd(long a, long b);
void printfrac(long a, long b);
int main (void) {
long a1;
long b1;
long a2;
long b2;
char op[4] = {'+', '-', '*', '/'};
int i;
scanf("%ld/%ld %ld/%ld", &a1, &b1, &a2, &b2);
for(i = 0; i < 4; i++) {
printfrac(a1, b1);
printf(" %c ", op[i]);
printfrac(a2, b2);
printf(" = ");
// 我们使用的是long, 这里不用同分, 直接计算
switch (op[i]) {
case '+':
printfrac(a1 * b2 + a2 * b1, b1 * b2);
break;
case '-':
printfrac(a1 * b2 - a2 * b1, b1 * b2);
break;
case '*':
printfrac(a1 * a2, b1 * b2);
break;
case '/':
printfrac(a1 * b2, b1 * a2);
break;
}
printf("
");
}
return 0;
}
long getgcd (long a, long b) {
// 用其它求gcd的方法, 很可能导致
// 后两个测试点超时, 原因不明
long r;
while ((r = a % b)) {
a = b;
b = r;
}
return b;
}
void printfrac (long a, long b) {
/*
这里的a, b有多种情况, 正正, 正负, 负负都有可能
再下面判断符号时, 充分利用了负负的正的思想
*/
if (b == 0) {
printf("Inf");
return;
}
int sign = 1;
long gcd;
if (a < 0) {
a = -a;
sign = sign * -1;
}
if (b < 0) {
b = -b;
sign = sign * -1;
}
gcd = getgcd(a, b);
a = a / gcd;
b = b / gcd;
if (sign == -1) printf("(-");
if (b == 1) {
printf("%ld", a); // 整数
} else if (a > b) {
printf("%ld %ld/%ld", a / b, a % b, b);
} else {
printf("%ld/%ld", a, b); // a < b
}
if (sign == -1) printf(")");
}