【OJ-UVa202】

重点

一. 如何判断出现循环小数

我冥思苦想几天,终于自己独立想出个简单办法。我用自己的 三星 Note9 Pen在手机上演算的。(图为当时草稿可能有错,以文章文字为主。)

其实这些算术题目,最好用简单案例推导。以前看公开课,老外上课,都是讲的特别简单,但是每个重点都会用例子讲解,并且例子讲解的超级详细,听我的昏昏欲睡。后来才觉得仔细研究例子才是最快的办法,比干用脑袋有效。(因为这不是数学证明题,无需严谨的推导,能依葫芦画瓢即可,凭直觉猜出逻辑即可)

说正题 ,如 76/25。 图中 S 是 存放 商 的数组, Y 是存放 余数的数组。以下对照图片看更有效。

1. 首先,被除数 是76, 除数 是25。

2. 第一个商 是 3 ,余数 是 1,都存到数组里,后面要用。

2. 余数1*10 = 10,作为新的被除数。除数永远不变。

3. 第二个商 是0 ,余数是 10,保存待用。

4. 余数10*10= 100,作为新的 被除数。除数不变。

5. 第三个商是4,余数是 0,保存待用。

6. 余数0*10=0, 作为新被除数

7. 第四个商是0,余数是0,保存待用。

扫描二维码关注公众号,回复: 9487743 查看本文章

8. 发现第四个余数,和第三个余数一样的。余数一样意味什么呢,意味着下一步的被除数都是一样的,除数又永远不变,下一步的商 就也是一样的。之后陷入无限的一样,陷入循环。

然后,这时就可以确定:第四个商就是最小的循环体。

推广一下,随便举个例子。

i = 0,1,2,3,4,5

S=3,0,4,5,6,7

                       |-------|

Y=1,10,8,9,2,8

                  |----------|

当 i = 5(第六个余数)时,和 i = 2(第三个余数)余数相同,则说明后面就可以陷入循环了,后面的商肯定是 567567...(可以自己演算下为什么是 567 ,而不是 4567)。

则此时,循环部分的起始位就是 i=3,结束位是 i=5。

二、代码

将上面的伪代码写成C或者C++即可。

第一次,Y 数组和 S 数组设置为200大小,被爆 Runtime Error,后改为3000,AC通过。但从题目我看不出来,具体需要多大。

判断循环小数

题目要点

1. EOF作为输入结束标志

scanf() 和 getchar() 都可以捕获 EOF ,EOF其实就是被define为-1的无符号整数。

2. 输出最短的循环小数

0.0333... 循环部分就是 3 ,从第二个小数位开始,长度是1

0.2500...循环部分是0,从第三个小数位开始,长度是0

5/43 = 0.(116279069767441860465) 循环部分是116...,从第一个小数位开始,长度是21
1/397 = 0.(00251889168765743073047858942065491183879093198992...)循环部分是0025...992...,从第一个小数位开始,长度是99

3. 输出格式

循环部分小于50位的,直接输出;多于50位的,只输出前面50位。前后括号和省略号不算在50位里面。

1/397 = 0.(00251889168765743073047858942065491183879093198992...)
   99 = number of digits in repeating cycle

%d/%d(空格1个)=(空格1个)%d.(%d...)

(空格3个)%d(空格1个)=(空格1个)number of....

(\n换行)

AC代码

我不保证是最优的代码,但是可以AC。我按照黑书(算法设计竞赛第二版)做的,虽然C/C++/JAVA也熟,但还是按照书本顺序,只用C语言实现,所以看着有些臃肿。

//3-8.c UVa202,2019-03-23
//余数一旦出现过,循环就开始了


#include <stdio.h>
#include <string.h>
#include <math.h>

//#define LOCAL

	int Y_arr[3000];
	int S_arr[3000];

int ifRepeat(int *arr, int len , int a ){
	//只需和之前的比较,len-1 是当前元素 a
	for (int i = 0; i < len - 1; ++i)
	{
		if (arr[i] == a)
		{
			return i;
		}
	}
	return -1;
}


int main(){


#ifdef LOCAL
    freopen("input.txt", "r", stdin);
    // freopen("output.txt", "w", stdout)
#endif


	int a = 0, b= 0;

	int i =0 ,beichushu = 0, chushu = 0;
	int s = 0, y = 0;	//商 ,余数

	int cycleBgnInx = 0, cycleEndInx = 0,cycleLen = 0;	//循环开始,循环结束


	while(scanf("%d %d",&a, &b)!=EOF){

		memset(Y_arr, 0, sizeof(Y_arr));
		memset(S_arr, 0, sizeof(S_arr));

		beichushu = a;
		chushu = b;

		for (i = 0; ; ++i)
		{
			s = beichushu / chushu;
			y = beichushu % chushu;

			S_arr[i] = s;
			Y_arr[i] = y;

			//余数若出现过,则后面的计算是重复值
			if(ifRepeat(Y_arr, i+1 ,y) != -1)
			{
				cycleBgnInx = ifRepeat(Y_arr, i+1 ,y)+1;
				cycleEndInx = i ;
				cycleLen = cycleEndInx - cycleBgnInx + 1;
				break;
			}else{
				beichushu = y * 10;
			}

		}

		//allshang[0-recycleEndInx] is result
		//length is recycleEndInx+1
		// printf("lenth is: %d\n", recycleEndInx);
		printf("%d/%d = %d.", a, b, S_arr[0]);

		//output not cycle part
		for (i = 1; i < cycleBgnInx ; ++i)
		{
			printf("%d", S_arr[i]);
		}

		printf("(");

		//output cycle part
		if ( cycleLen <= 50)
		{
			for (i = cycleBgnInx; i <= cycleEndInx ; ++i)
			{
				printf("%d", S_arr[i]);
			}
		}else{
			for (i = cycleBgnInx; i < 50+cycleBgnInx ; ++i)
			{
				printf("%d", S_arr[i]);
			}
			printf("...");
		}


		printf(")\n");
 
		printf("   %d = number of digits in repeating cycle\n", cycleLen);


		printf("\n");

	}

	return 0;
}
发布了58 篇原创文章 · 获赞 44 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/qilei2010/article/details/89163816