来源:Vijos 1696
数与连分数
描述
写一个程序…可以实现在连分数和分数之间的互相转换…
样例1
样例输入1
[2;3,7]
51/22
样例输出1
51/22
[2;3,7]
提示
多组测试数据:
…每一个测试点有多组数据…数据的组数不超过100组…
约分:
计算结果最后是要约分的…但是…在分数转向连分数的时候…
我们不保证输入的数据是约分…
Range:
数字的规模都很小…
也就是它们都不会超过longint范围里…
包括中间的数据…
连分数的项数也不会超过100项…
限制:
出题人不透露
考点:模拟(枚举?)
这个题只需要了解连分数的知识就应该可以比较容易解决,我认为这个题就仅仅是模拟两个算法:数-连分数,连分数-数;不知道这个题为什么被打上了枚举的标签(如果你认为顺序或逆序遍历也算枚举的话当我没说)。
首先上连分数的知识,这里不想给具体定义,就给个实例,应该很容易理解:
右边对应的表示形式是[3;4,12,4],理解后很容易构思算法。上代码:
#include <iostream>
#include <cstring>
#define MAXN 307
#define IsDigit(x) (x >= '0' && x <= '9')
using namespace std;
char str[MAXN];
int len, sum, cun[MAXN], res[MAXN];
int gcd(int a, int b)
{
return (b == 0) ? a : gcd(b, a % b);
}
//连分数-数
void Work1()
{
int sup, a, b, pos = 0, t = 1;
//提取数字并存储在数组里
while (t < len)
{
sum = 0;
while (IsDigit(str[t]) and t < len)
sum = sum * 10 + str[t++] - '0';
cun[pos++] = sum;
++t;
}
a = 1, b = cun[pos - 1];
for (int i = pos - 2; i >= 0; --i)
a += cun[i] * b, swap(a, b);
//特例
if (a == 1) cout << b << endl;
else cout << b << "/" << a << endl;
}
//数-连分数
void Work2()
{
int a, b, t = 0, tmp, GCD;
//同上
while (t < len)
{
sum = 0;
while (IsDigit(str[t]) and t < len)
sum = sum * 10 + str[t++] - '0';
if (str[t] == '/') a = sum;
++t;
}
b = sum, t = 0;
//约分
GCD = gcd(a, b), a /= GCD, b /= GCD;
//特例
if (b == 1) cout << "[" << a / b << "]\n";
else
{
while (b != 1)
{
tmp = a / b;
res[t++] = tmp, a -= tmp * b;
swap(a, b);
}
res[t++] = a;
cout << "[" << res[0] << ";";
for (int i = 1; i < t - 1; ++i)
cout << res[i] << ",";
cout << res[t - 1] << "]" << endl;
}
}
int main()
{
while (cin >> str)
{
len = strlen(str);
if (str[len - 1] == ']') Work1();
else Work2();
}
return 0;
}
需要注意的几点:
1.这个题输入输出比较麻烦,需要将字符串中的数字提取出来,还要把计算后的结果用题目要求的形式输出;
2.约分的问题:用辗转相除法求最大公约数,上下同除即可得到最简分数;
3.某些特例:[4] = 4,不是4/1; 4/1 = [4],不是[4;]。