ACMSTEP 2.1.8 小数化分数 2 //数论 数学 没AC

原题地址

这道题我的代码没有AC 我用的是 小学奥数的思想做的 可以参见代码 但是 混合部分 出错 一直找不出来错误。




相关知识

小学奥数中关于小数化分数的解法:

纯循环小数的分母都是9,9的个数与循环节的位数相同,分子就是循环节,最后要化简。比如0.3(3循环)=3/9=1/3   0.37(37循环)=37/99
混循环小数所化成的分数的分母由9和0组成,分母中9的个数与循环小数的循环节的位数相同(就是一位循环小数就是1个9,两位循环小数就是2个9),9后面的0的个数与循环小数小数点后不循环的位数相同;分子则是小数点后不循环的部分与第一个循环节所组成的多位数与不循环部分组成的多位数的差,如果这样所得的分数不是最简分数,还需要将其化简。例如:0.12(2循环),因为循环部分是一位(就是2),分母里就有1个9,不循环部分也是一位(就是1),分母里就有一个0,所以分母是90,分子就是12-1=11,  0.12(2循环)=11/90;再比如0.123(23循环),分母就是990,分子是123-1=122,这个分数是122/990=61/495;如果是0.123(3循环),则分母是900,分子是123-12=111,这个分数是111/900=37/300

这道题可以用的想法

众所周知,有限小数是十进分数的另一种表现形式,因此,任何一个有限小数都可以直接写成十分之几、百分之几、千分之几……的数。那么无限小数能否化成分数? 

首先我们要明确,无限小数可按照小数部分是否循环分成两类:无限循环小数和无限不循环小数。无限不循环小数不能化分数,这在中学将会得到详尽的解释;无限循环小数是可以化成分数的。那么,无限循环小数又是如何化分数的呢?由于它的小数部分位数是无限的,显然不可能写成十分之几、百分之几、千分之几……的数。其实,循环小数化分数难就难在无限的小数位数。所以我就从这里入手,想办法“剪掉”无限循环小数的“大尾巴”。策略就是用扩倍的方法,把无限循环小数扩大十倍、一百倍或一千倍……使扩大后的无限循环小数与原无限循环小数的“大尾巴”完全相同,然后这两个数相减,“大尾巴”不就剪掉了吗!我们来看两个例子:

⑴    把0.4747……和0.33……化成分数。

想1:        0.4747……×100=47.4747……   

0.4747……×100-0.4747……=47.4747……-0.4747……

(100-1)×0.4747……=47

即99×0.4747…… =47 

那么  0.4747……=47/99

 

想2: 0.33……×10=3.33……

0.33……×10-0.33……=3.33…-0.33……

 (10-1) ×0.33……=3

即9×0.33……=3

 那么0.33……=3/9=1/3

由此可见, 纯循环小数化分数,它的小数部分可以写成这样的分数:纯循环小数的循环节最少位数是几,分母就是由几个9组成的数;分子是纯循环小数中一个循环节组成的数。

⑵把0.4777……和0.325656……化成分数。

想1:0.4777……×10=4.777……①

0.4777……×100=47.77……②

用②-①即得: 

0.4777……×90=47-4

所以, 0.4777……=43/90

 

想2:0.325656……×100=32.5656……①

0.325656……×10000=3256.56……②

用②-①即得: 

0.325656……×9900=3256.5656……-32.5656……

0.325656……×9900=3256-32

所以, 0.325656……=3224/9900

将纯循环小数改写成分数,分子是一个循环节的数字组成的数;分母各位数字都是9,9的个数与循环节中的数字的个数相同.

  将混循环小数改写成分数,分子是不循环部分与第一个循环节连成的数字组成的数,减去不循环部分数字组成的数之差;分母的头几位数字是9,末几位数字是0,9的个数跟循环节的数位相同,0的个数跟不循环部分的数位相同.


我的代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
int wei(long long x)
{
	int k=0;
	while (x!=0)
	{
		x = x/10;
		++k;
	}
	return k;
}

long long gcd(long long x , long long y)
{
	if (!x || !y) return x>y?x:y;
	for (long long t; t=x%y;x=y,y=t);
	return y;
}
void normalf(long long x)
{
	
	long long len = wei(x);
	long long fm = (long long)pow(10,(double)len);//分母 
	long long gcdn = gcd(x,fm);
	long long fz = x / gcdn;
	fm = fm / gcdn;
	cout<<fz<<"/"<<fm<<endl; 	                                                                 
}
void xunhuan(long long x)
{
	
	long long len = wei(x);
	long long fm = (long long)pow(10,(double)len)-1;//分母 
	long long gcdn = gcd(x,fm);
	long long fz = x / gcdn;
	fm = fm / gcdn;
	cout<<fz<<"/"<<fm<<endl; 	
}                                                                   

void hunhe(long long b, long long x)
{
	long long lena = wei(b);
	long long lenb = wei(x);
	long long bfm = ((long long)pow(10,(double)lenb)-1)* (long long)pow(10,(double)lena);//循环部分的分母
	long long gcdn = gcd(x,bfm);
	long long bfz = x / gcdn; bfm = bfm / gcdn;
	//相加
	long long afm = (long long)pow(10,(double)lena);//前面不循环的小数的分母
	long long afz = b;
	//通分
	long long fm = afm * bfm / gcd (afm,bfm);
 	long long fz = (fm / afm)*afz + (fm / bfm) * bfz;
 	gcdn = gcd(fz ,fm);
 	fm = fm /gcdn;
 	fz = fz / gcdn;
 	cout<<fz<<"/"<<fm<<endl;                        	 
	
}
int main()
{
	freopen("c:\\in.txt","r",stdin);
	char str[20];
	long long flag , len , xs ,bef ,i;
	long long cases;
	cin>>cases;
	while (cases--)
	{
		cin>>str;
		len = strlen(str);
		flag = 0;
		for (i=0; i<len ;i++)
		{
			if (str[i]=='(' && str[i-1]!='.')
			{
				flag =2; break;
			}
			else if (str[i]=='(' && str[i-1] == '.')
			{
				flag = 1; break;
			}
		}
		xs = bef = 0;
		if (flag == 0)
		{
			sscanf(str,"0.%d",&xs);
			normalf(xs);
		}
		else if (flag == 1)
		{
			sscanf (str, "0.(%d)",&xs);
			xunhuan(xs);
		}
		else if (flag == 2)
		{
			sscanf (str,"0.%d(%d)",&bef,&xs );
			hunhe(bef,xs);
		}
	} 
	return 0;
}





AC代码

#include <iostream>
using namespace std;
int f(int u,int v)
{
    while(u%v)
    {
      int w=u%v;
      u=v;
      v=w;
    }
    return v;
}
int main()
{
    int t;
    while(cin>>t)
    {
        while(t--)
        {
            char a[15];
            cin>>a;
            int p=0,q=0,t=0,x=0,y,k=1,l=1,max;
            for(int i=2;a[i]!='\0';i++)
            {
                if(!t && a[i]!='(') {p++;x*=10;x+=a[i]-'0';}
                if(t && a[i]!=')') {q++;y*=10;y+=a[i]-'0';}
                if(a[i]=='(') {t=1;y=x;q=p;}
            }
            if(!q)
            {
                while(p--)
                    k*=10;
                max=f(x,k);
                x/=max;
                k/=max;
                cout<<x<<'/'<<k<<endl;
            }
            else
            {
                int m=y-x;
                while(p--)
                    k*=10;
                while(q--)
                    l*=10;
                int n=l-k;
                max=f(m,n);
                m/=max;
                n/=max;
                cout<<m<<'/'<<n<<endl;
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值