博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
循环小数 uva202
阅读量:4114 次
发布时间:2019-05-25

本文共 2855 字,大约阅读时间需要 9 分钟。

题目名称:循环小数

题目描述:

输入整数a和b a大于等于0小于等于3000,b大于等于1小于等于3000,输出a/b的循环小数表示以及循环节长度。如果循环周期大于50,只显示50位,之后的全部用……表示

样例:

Alt text

题目分析:
①所谓的循环小数,也就是我们理解的当每步作除法时候,会出现了重复的商,那个循环小数的周期肯定就在两个重复的商之间。
②现在就转化为类似于找周期的问题了,找重复出现的商,我们最常见想到的办法就是记录所有的商,每算出一个新的商,之后就顺序查找看该商是否出现过,这就比较复杂了,复杂度为O(n^2)
③改进方法就是我们可以考虑用一个数组记录某个商是否出现过,这样来做复杂度就为O(n)
③我们需要设置的变量
输入:分子numerator 分母denominator
商 quotient
商的整数部分 integer
商的小数部分 digits[]
余数是否存在 reminder_exist[]
余数存在的位置 reminder_pos
商是否存在循环 found_cycle
商的小数部分开始循环的位置 cycle_pos
循环的长度 cycle_len
循环长度的限制 display_limit

算法思路

a)首先我们要表示商的小数点左边的部分,并且由于分子一直在变化,所以我们要设置一个新的变量保存下初始的分子,方便之后的输出

b)查找循环,由简单的数学知识可知,如果某两步计算的余数相等,那么他们之间的这些计算就是属于我们的循环小数了,所以我们需要就是找每步计算余数相等的,我们要知道他们分别的位置,这里我们采用两个数组来区分一个是reminder_exist[]这里保持,哪个余数存在,对应的值就为1,所以我们可以通过检测这个数组的值来找循环,之后因为我们还需要之前第一次出现这个循环的位置,所以我们还需要有一个数组保存第几次运算出现哪个余数。之后再用第二次出现计算次数减去第一次出现的次数,我们就可以得到循环节的长度了。而且每一步计算得到的商需要保存在一个数组中,这里命名为digits

c)最后再比较下计算最后一次与50进行比较,来按要求输出。

学习笔记:

本题最核心的算法在于,我们怎么去找出循环小数的循环体个数了,循环体初始位置和最后位置。

通过数学知识可以知道找余数相同的时候,每次计算得到的余数放在一个数组中,且数组对于位置为1,代表存在这个余数,之后再通过一个循环找这个位置为1的时刻,这就是余数相同的时候,并且用一个数组保存计算的次数,取每次计算得到的商保存在digits[]中,所以每次余数对应三个数组的值分别问商、计算次数、是否存在的。

//.c#include 
#include
#define maxn 100#define display_limit 50#define max_INT 10000int digits[maxn];int reminder_exist[max_INT];int reminder_pos[max_INT];int main(){ int numerator,denominator,quotient,reminder; while(scanf("%d%d", &numerator, &denominator) != EOF && denominator) { //初始化数组和商的整数部分 int original_numerator = numerator; memset(reminder_exist, 0, sizeof(reminder_exist)); memset(reminder_pos, 0, sizeof(reminder_pos)); quotient = numerator/denominator; reminder = numerator%denominator; int integer = quotient; //找出循环 int found_cycle = 0; int cycle_pos = maxn; int cycle_len = 0; int i = 0; for(i = 0; i <= maxn; i++) { if(reminder_exist[reminder]) { cycle_pos = reminder_pos[reminder]; cycle_len = i - cycle_pos; break; } else { reminder_exist[reminder] = 1; reminder_pos[reminder] = i; } numerator = reminder * 10; quotient = numerator/denominator; reminder = numerator%denominator; digits[i] = quotient; } //输出 printf("%d/%d = %d.(",original_numerator, denominator, integer); if(i <= display_limit) { for(int j = cycle_pos; j < i; j++) { printf("%d", digits[j]); } } else { for(int j = cycle_pos; j < display_limit;j++) printf("%d", digits[j]); printf("..."); } printf(")\n"); printf("%d = number of digits in repeating cycle\n", cycle_len); } return 0;}

转载地址:http://kugsi.baihongyu.com/

你可能感兴趣的文章
网络通信Socket编程基础
查看>>
C#.Net Socket网络通讯编程
查看>>
socket编程学习笔记
查看>>
TCP与UDP区别
查看>>
图库资源
查看>>
股票只有两个字:“等待”
查看>>
C#增加语言资源文件的文件
查看>>
MYSQLDUMP备份数据库和MYSQL还原数据库
查看>>
Mysql常用命令行大全
查看>>
银行知识点
查看>>
在.net中未能用trycatch捕获到的异常处理
查看>>
c# winfrom资源文件的调用和路径全解
查看>>
salesforce json
查看>>
jquery判断checked的三种方法:
查看>>
将dom对象转成jquery对象 和不能编辑日期控件的文本框
查看>>
学一点Git–20分钟git快速上手
查看>>
extjs 基础知识点1
查看>>
使用Ext.define自定义类
查看>>
extjs基础知识点归纳二
查看>>
日语语法部分总结
查看>>