WA的代码:
#include<iostream> #include<string.h> #include<stdio.h> #define LL long long #define maxn 1000+5//最多的小数位数 using namespace std; double a[maxn]; const double eps=1e-10; double abs(double n) { return n>0 ? n:-n; } int find(int cnt)//关键 {//判断第cnt个数是否在前面出现过 for (int i=1;i<cnt;i++) { if (abs(a[i]-a[cnt])<eps) return i; } return 0; } int main() { LL n,m; int cas=0; while(~scanf("%I64d/%I64d",&n,&m)) { cas++; double ans=(n+0.0)/(m+0.0); ans=ans-(int)ans; int cnt=1;a[1]=ans; int ch; while ( (ch=find(cnt))==0 ) { ans=ans*2; ans=ans-(int)ans;//应该判余数 cnt++; a[cnt]=ans; } printf("Case #%d: %d,%d ",cas,ch,cnt-ch); } return 0; }
我们主要来说说是怎么WA的
一句话总结,正确的算法,有限的存储精度。
思路描述:
1、原理:重复乘2,取首位。
然后我就就想简化判断,只要出现重复的小数部分,那一定是又开始了一个新的循环。
2、结果悲剧了,错误有二:
i. double型的好像不能直接判断a==b,会有判断误差,反正像是0.2==0.2这样的都判断不出
ii. 后来我就想通过eps约束,(abs(a-b)< eps ), 一直W,后来才想到,比如1/199213,这样的数据,它本身的小数部分就有10^6位,计算机是不可能存储下来的,double本来就是模糊存储。 再者,eps不可能兼顾所有的数据 (以后少用)。
下面是AC的代码