关于算法-数据结构:PAT甲级1060-Are-They-Equal

3次阅读

共计 3098 个字符,预计需要花费 8 分钟才能阅读完成。

题目粗心:

给定两个位数不超过 100 的非负浮点数, 如果保留 n 位有效数字的状况下写成 0.@@@@*10^@的模式, 如果两者雷同, 则输入 YES 和该数字, 如果不同输入 NO 并且别离输入 2 个数。

算法思路:

认真思考下, 这种模式和科学技术法很类似然而有不同于迷信计数法, 因为后面肯定得是 0. 结尾,那么输出的数字的模式依照情理来说只有一种
那就是 $abcd.efg$, 然而在这里认真分成 2 类, 一类就是 $0.efg$ 的模式, 一类就是 $abcd.@@@$ 的模式 (如同和没说一样, 哈哈哈), 这里把第一类分进去是因为在解决第二类的时候会呈现 $abcd$ 全副是 0 的状况( 这是一个陷阱), 这样就进化到了第一类, 而后就是输出的数字有可能原本就是第一类, 这样不便代码解耦(个人观点), 接下来就具体说这 2 类数字的解决办法.

第一类 $0.efg$

首选咱们晓得最初肯定是 0. 结尾, 所以应用 string r="0." 保留最初后果, 这类数字分为 2 种状况, 一种就是小数点前面全是 0, 这种状况下就
间接让 r 前面增加 n 个 0 和 10^0 即可 ( 这也是一个陷阱 ),另外一种就是小数点前面有不为 0 的数字, 那么用 index 保留其地位, 让 r 增加原字符串的 index 到最初地位的子串, 留神如果该子串的长度s.size()-index<n,则得在前面补充 0, 使得其小数点前面的无效位为 n( 这也是一个陷阱 ), 而后再增加指数局部, 指数的次幂pos+1-index(index-pos-1 就是小数点到不为 0 之间 0 的个数, 相反数就是指数局部)。最初返回 r 即可。该类数字应用 type1 函数解决。

第二类 $abcd.@@@$(蕴含整数)

这类数字也分为 2 种状况, 第一种状况就是小数点后面全副是 0, 这样的数字 (比方 0000.@@@, 等效于 0.@@@) 等价于第一类数字, 间接将小数点前
面的一个 0 到最初地位截断, 而后调用 type1 解决即可, 第二种状况就是小数点后面有不为 0 的数字, 这样咱们用 index 保留小数点后面不为 0 的数字的地位, 同样的让 r 初始化为 ”0.” 而后再移除小数点(移到后面去了), 将 index 前面 n 位子字符串拼接到 r 的前面, 如果该子字符串的长度s.size()-index<n, 要在前面补 0, 最初再增加指数局部, 指数的次幂为pos-index(pos-index 为小数点后面不为 0 数字的个数, 也就是小数点挪动的位数)

留神点:

1、数字签名可能会有前导 0,比方 000 000.12 00004522145.155,测试点 2,4,6 考查,解决办法能够采取去除前导 0,这里是间接归类于第二类,而后会跳转到第一类,间接解决小数点前面的数字即可。
2、对于 000.00 的状况须要输入 0.@@@(n 个 @)*10^0,测试点 6 考查。
3、对于整数的解决,这里采纳在最初增加一个小数点演绎在第二类中。
4、对于自身不须要挪动小数点的状况,除了 000.00 这样的须要在最初增加 10^0 外,其余的点没有考查,也就是像 0.12 保留 2 位数字输入 0.12 和 0.12*10^0 都是能够的。

提交后果:

测试数据:

4 0000 0000.00 //YES 0.0000*10^0
4 00123.5678 0001235 //NO 0.123510^3 0.123510^4
3 0.0520 0.0521 // NO 0.52010^-1 0.52110^-1
4 00000.000000123 0.0000001230 // YES 0.1230*10^-6
4 00100.00000012 100.00000013 // YES 0.1000*10^3
5 0010.013 10.012 // NO 0.1001310^2 0.1001210^2
4 123.5678 123.5 // YES 0.1235*10^3
3 123.5678 123 // YES 0.123*10^3
4 123.0678 123 // YES 0.1230*10^3
3 0.000 0 // YES 0.000*10^0

AC 代码:

#include<cstdio>
#include<string>

using namespace std;

string type1(string s,int n,int pos){// 解决模式 0.***** 的字符串
    string r = "0.";// 保留最初后果 
    int index;// 保留小数点前面第一个不为 0 的地位 
    for(index=pos+1;index<s.size();++index){if(s[index]!='0') break;
    }
    if(index==s.size()){// 阐明小数点前面全副为 0(或者小数点前面没有了, 比方输出了 0), 取无效长度的 0, 而后增加 10^0 即可 
        for(int i=0;i<n;++i){// 最初一个测试点考查的就是这一点 
            r += "0";
        }
        r += "*10^0";
    }else{// 存在不为 0 的数字, 那么该数字前面 n 位为无效位, 不够补 0 
        r += s.substr(index,n);
        if(s.size()-index<n){// 阐明无效位长度不够, 得补 0 
            for(int i=0;i<n-(s.size()-index);++i){r += "0";}
        }
        r += "*10^"+to_string(pos+1-index);//index-pos- 1 就是小数点到不为 0 之间 0 的个数, 相反数就是指数局部 
    }
    return r;
} 

string type2(string s,int n,int pos){// 解决模式 abcd.***** 
    int index;// 保留小数点后面第一个不为 0 的地位
    string r;// 保留最初后果 
    for(index=0;index<pos;++index){if(s[index]!='0') break;
    } 
    if(index==pos){// 小数点后面全副是 0, 从小数点前面找, 转化为 type1 类型 
        s = s.substr(pos-1);// 截取 0.***** 局部 
        r = type1(s,n,1);//pos 地位就是 1 
    }else{// 小数点后面有不为 0 的局部 
        r += "0.";
        s.erase(s.begin()+pos);// 移除小数点 
        r += s.substr(index,n);// 截取 index 前面 n 为字符串, 不够补 0
        if(s.size()-index<n){// 无效位不够, 补 0 
            for(int i=0;i<n-(s.size()-index);++i){r += "0";} 
        } 
        r += "*10^"+to_string(pos-index);// 增加指数局部 
    }
    return r;
}

string process(string s,int n){// 将以后数字写成 0.***** 的模式并且保留 n 位 
    if(s.find(".")==string::npos){// 以后字符串没有小数点是整数 
        s += ".";// 在最初增加小数点 
    }
    int pos = s.find(".");// 取得小数点的下标 
    string r;// 保留最终后果 
    if(pos==1&&s[0]=='0'){// 该数字原本就是 0.**** 的模式 
        r = type1(s,n,pos);
    } else{//abcd.**** 的模式
        r = type2(s,n,pos);
    }
    return r; 
}

int main(){
    int n;
    string s1,s2;
    char t1[101],t2[101];
    scanf("%d %s %s",&n,t1,t2);
    s1 = t1;
    s2 = t2;
    s1 = process(s1,n);
    s2 = process(s2,n);
    if(s1==s2){printf("YES %s",s1.c_str());
    }else{printf("NO %s %s",s1.c_str(),s2.c_str());
    }
    return 0;
}
正文完
 0