UVA-202 Repeating Decimals

/* 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[N],  flag[N]; //三个数组分别对应商、余数,记录某个余数对应是在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;
}

原文地址:https://www.cnblogs.com/mofushaohua/p/7789546.html