1. 程式人生 > >hdu 1717 小數化分數2 (迴圈小數轉分數)

hdu 1717 小數化分數2 (迴圈小數轉分數)

本題可推出公式

首先跟你一個小數 令X= 0 . s1 s2 ..sn ( y1 y2 y3..ym ) 這樣的話我們把小數點分為三個部分,分別用三種顏色標記了!

我們可以把表示式轉換成:X * 10 ^n=s1s2..sn+0.y1y2..ym;    我們用S1替換 s1s2..sn ,Y替換 0.(y1y2..yn), 然後可以把表示式寫成: X * 10^n=S1 + Y;  然後 Y=0.(y1y2..ym) 變形一下:Y * 10 ^m=y1y2..ym + Y; 在這裡我們另y1y2..ym等於S2;

宗上所述:我們得到兩個表示式 X * 10^n=S1 +  Y;    Y * 10^m=S2 + Y; 然後將兩個式子合併成一個用表示式,

$$\frac{s2 + (10^m-1)*s1}{10^n * ( 10^m -1 )}$$然後就可以根據這個公式,求出分子分母的 最大公約式 然後化簡 就可以了


由此只需算出s1,s2,m,n即可,從字串中讀數使用sscanf,格式化讀入可用 sscanf(c,"0.%d(%d)",&s1,&s2); 。

算m,n時不能按s1,s2位數算,因為前面可能有0,如0.0(1)這個數、

算平方真心不能用pow,精度太低了,,,wa了幾次

程式碼:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;

int gcd(long long a,long long b){
    if(b==0)return a;
    else return gcd(b,a%b);
}
char c[20];
int main(){
    int T;
    cin>>T;
    while(T--){
        scanf("%s",c);
        int s1,s2;
        int flag=1;
        for(int i=1;i<strlen(c);i++){
            if(c[i]=='('){flag=0;break;}
        }
        if(flag){ sscanf(c,"0.%d",&s1); s2=0;}
        else if(c[2]=='(') {sscanf(c,"0.(%d)",&s2); s1=0;}
        else sscanf(c,"0.%d(%d)",&s1,&s2);
        char t[20];
        int m=0,n=0;
        if(flag) {m=strlen(c)-2;n=0;}
        else {
            int i;
            for(i=2;i<strlen(c);i++){
                if(c[i]!='(') m++;
                else break;
            }
            i++;
            for(;i<strlen(c);i++){
                if(c[i]!=')') n++;
                else break;
            }
        }
        int k1=1;
        int k2=1;
        for(int i=1;i<=m;i++){
            k1*=10;
        }
        for(int i=1;i<=n;i++){
            k2*=10;
        }

        long long a=s2+s1*(k2-1);
        long long b=(k2-1)*k1;

        if(flag) {a=s1;b=k1;}
        int k=gcd(a,b);
        a/=k;
        b/=k;
        printf("%I64d/%I64d\n",a,b);
    }
    return 0;
}