习题
3-8
循环小数(
Repeating Decimals, ACM/ICPC World Finals 1990, UVa202
)
输入整数 a 和 b ( 0≤ a ≤3000 , 1≤ b ≤3000 ),输出 a/b 的循环小数表示以及循环节长度。 例
输入整数 a 和 b ( 0≤ a ≤3000 , 1≤ b ≤3000 ),输出 a/b 的循环小数表示以及循环节长度。 例
如a=5,b=43,小数表示为0.(116279069767441860465),循环节长度为21。
点击打开链接链接在这里
前面的练习写过一题这样的小数输出题,
整数,
小数点,
题目意思有三种输出情况,
1 50以内能除尽,那就循环0;
2 50以内有循环单体,那就是当被除数与最开始进入循环相同的时候结束;
3 50以内除不尽,那就全部输出;
#include <bits/stdc++.h>
using namespace std;
int s,tp,a,len,num;
int rep[51];
int main()
{
//freopen("input.txt","r",stdin);
while(~scanf("%d%d",&s,&a)){
printf("%d/%d = ",s,a);
printf("%d.",s/a);
s=(s-s/a*a);
len=0,num=0;
tp=s;
while(s!=0){
s*=10;
//cout<<"s="<<s<<endl;
++len;
if(len<=50) rep[len]=s/a;
s=(s-s/a*a);
if(s==tp) break;
}
if(len>50){
printf("(");
for(int i=1;i<=50;i++){
printf("%d",rep[i]);
}
printf("...)");
num=len;
}
else if(s==0){
for(int i=1;i<=len;i++){
printf("%d",rep[i]);
}
printf("(0)");
num=1;
}
else{
printf("(");
for(int i=1;i<=len;i++){
printf("%d",rep[i]);
}
printf(")");
num=len;
}
printf("\n %d = number of digits in repeating cycle\n\n",num);
}
return 0;
}
上面那个代码提交到oj是错误的,原因有很多,主要是无法处理1/6,1/300这类的循环小数;因为判断循环的方法有问题;
正确的循环方法是任意一个第一次重复出现的s的pos1为循环节的起点,那重复的s之间的距离就是长度;
改进的AC代码如下
用了gcd对分数化简;
然后用cycle保存下标为s的情况是否出现过,first保存位置,second是bool;
#include <bits/stdc++.h>
using namespace std;
int len,s,a,num,pos1,pos2;
typedef pair<int,bool> P;
P cycle[30000];
int rep[51];
int gcd(int small,int big){
if(small>big) swap(small,big);
while(small!=0){
if(small>big) swap(small,big);
int tp=small;
small=big%small;
big=tp;
}
return big;
}
void simplify(){
int o=gcd(s,a);
s/=o;
a/=o;
}
int main()
{
//freopen("input.txt","r",stdin);
while(~scanf("%d%d",&s,&a)){
memset(cycle,0,sizeof(cycle));
len=0;
num=0;
printf("%d/%d = %d.",s,a,s/a);
simplify();
s=10*(s%a);
while(1){
len++;
//cout<<endl<<"s="<<s<<" "<<"len="<<len<<endl;
//cout<<"1--"<<cycle[s].first<<' '<<"2--"<<cycle[s].second<<endl;
if(cycle[s].second==true){
pos1=cycle[s].first;
pos2=len;
break;
}
else{
cycle[s].first=len;
cycle[s].second=true;
}
//cout<<"after"<<cycle[s].first<<' '<<cycle[s].second<<endl;
if(len<=50) rep[len]=s/a;
s=10*(s%a);
}
if(len>50){
for(int i=1;i<=50;i++){
if(i==pos1)printf("(");
printf("%d",rep[i]);
}
printf("...)\n");
}
else{
for(int i=1;i<=len-1;i++){
if(i==pos1)printf("(");
printf("%d",rep[i]);
}
printf(")\n");
}
num=pos2-pos1;
printf(" %d = number of digits in repeating cycle\n\n",num);
}
return 0;
}