您的位置:首页 > 其它

UVA-202 Repeating Decimals

2017-08-19 14:46 344 查看
/* http://blog.csdn.net/mobius_strip/article/details/39870555 这题涉及到了抽屉原理,也叫鸽巢原理,有时间不妨看看,我下载了相关文档 http://www.xuebuyuan.com/2224752.html 这个blog讲解得比较细致易懂,但是它的代码是RE的,不过思路和下面那串代码也是大同小异的,就没有改代码了

这题和一般的除法处理也很类似:不断被除数除以除数,商放入数组以备输出,余数(先保存,后面解释原因)*10作为新的被除数,再去得到除数...依次类推

为什么保存余数?
按照上面的描述,以及除法的规则,我们可以发现,只要在不断更新过程中,出现了之前出现过的余数,则循环节找到了,因为此后,就是这个相等的余数*10/被除数作商,取模被除数作余数,循环往复,关键还是找规律,发现结合除法的规则,这种情况,刚好就是找到了循环节的情况

可能用抽屉原理以后,理解这个会更快,不过目前也能想明白

此外,注意下左括号输出的条件,是在 i到min(50, cnt-1)之间,是否满足最后留下的a,所对应的位置flag[a]是等于i的,这点一定要想明白

又及,既然i从1开始,那么第一个余数,就应该是flag[a % b] = 1;(a和b没变化前),但那时对于q的处理,我们却是q[0] = a / b; 这就说明,在我的代码中,q数组并不和 r数组和flag数组,一一同步变化...这点一定一定要小心,当初就是一直错了这里,没有转过弯来

再次说明flag[i]== j意味着,在第j此做除法时,得到的余数时i,如果发现flag[i]不为0,说明前面的除法中,已经出现了余数为i的情况,也就意味着,找到了循环节

最后,这题的格式,又忘记格式控制了,耐心细致!WA使人崩溃,但如果时PE的话,真的十分可惜,尽量减少罚时
*/

#include <iostream>
#include <cstring>
//#include <bits/stdc++.h>
using namespace std;
const int N = 5000; //注意数组不可开太小,否则RE
int q
,  flag
; //三个数组分别对应商、余数,记录某个余数对应是在flag数组哪位出现,标记是否找到循环节,何处找到

int main()
{
int a, b, cnt;
while (cin >> a >> b)
{
int tp = a;
memset(flag, 0, sizeof(flag));
q[0] = a / b;
a %= b;
for (cnt = 1; a && !flag[a]; cnt++) // 退出这层循环,可能是因为余数为0了,也有可能是因为找到了循环节
{
flag[a] = cnt;
q[cnt] = a * 10 / b;
a = a * 10 % b;// 很符合我们除法的规律,将余数*10再除以除数得商
}

//		for (int i = 0; i < cnt; i++) cout << q[i] << " ";

cout << tp << "/" << b << " = " << q[0] << ".";
//注意这几个 if-else 的出场顺序十分重要,有些虽然最后n为0,但不可以一开始就输出 (0,例如这组数据 76 25

for (int i = 1; i < cnt && i <= 50; i++)
{
if (a && flag[a] == i) //整除的情况后面有分支单独处理,此步考虑有循环节的情况,且此句对应着,现在就是碰到了循环节
cout << "(";
cout << q[i];
}
if (!a) cout << "(0";
if (cnt > 50) cout << "...";
cout << ")" << endl;

//	cout << "test: " << a << " " << flag[a] << endl;
cout << "   " << (!a?1:cnt - flag[a]) << " = number of digits in repeating cycle" << endl << endl;
//flag[a]找对应余数为a的位置
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息