C/C++ 【华为机试】输入一个真分数,将该分数分解为埃及分数。

题目:

  • 链接:牛客网华为机试题
  • 分子为1的分数称为埃及分数。现输入一个真分数(分子比分母小的分数,叫做真分数),请将该分数分解为埃及分数。
  • 如:8/11 = 1/2+1/5+1/55+1/110。
  • 输入描述:

输入一个真分数,String型

  • 输出描述:

输出分解后的string

  • 示例:

样例输入:

8/11

样例输出:

1/2+1/5+1/55+1/110

解题思路1:
【贪心算法】
设a、b为互质正整数,a < b 分数a/b 可用以下的步骤分解成若干个单位分数之和:

  • 步骤一: 用b 除以a,得商数q 及余数r。(r=b - a*q)
  • 步骤二:把a/b 记作:a/b=1/(q+1)+(a-r)/b(q+1)
  • 步骤三:重复步骤2,直到分解完毕

按照上面的方法:
3/7=1/3+2/21=1/3+1/11+1/231
13/23=1/2+3/46=1/2+1/16+1/368

 以上其实是数学家斐波那契提出的一种求解埃及分数的贪心算法,准确的算法表述应该是这样的:
 设某个真分数的分子为a,分母为b;
 把b除以a的商部分加1后的值作为埃及分数的某一个分母c;
 将a乘以c再减去b,作为新的a;
 将b乘以c,得到新的b;
 如果a大于1且能整除b,则最后一个分母为b/a;算法结束;
 或者,如果a等于1,则,最后一个分母为b;算法结束;
 否则重复上面的步骤。
 备注:事实上,后面判断a是否大于1和a是否等于1的两个判断可以合在一起,
 即:判断b%a是否等于0,最后一个分母为b/a,显然是正确的。

C/C++代码:

#include <iostream>
#include <cstring>
using namespace std;
int main(){
    string s;
    while(cin>>s){
	string s1, s2;
	int a = 0, b = 0, c = 0, r = 0;
        int n = s.length();
        int x = s.find('/');
        s1 = s.substr(0,x);
        s2 = s.substr(x+1);
//cout << "x:" << x << " s1: " << s1 << " s2: " << s2 << endl;
        for(int i = 0; i < s1.length(); i++){
        	a = a * 10 + s1[i]-'0';
		}
		for(int i = 0; i < s2.length(); i++){
        	b = b * 10 + s2[i]-'0';
		}
//cout << a << " " << b << endl;
        r = b%a;
        if(r == 0){
            cout << "1/" << b/a << endl;
            continue;
        }
        while( r != 0){
            c = b/a + 1;
            cout << "1/" << c << "+";
            a = a * c - b;
            b = b * c;
            r = b%a;
        }
        cout << "1/"<< b/a << endl;
    }
    return 0;
}

但是,由于这题的答案不唯一,在牛客网运行时的通过率仅为60%,所以,牛客网上的提供的标准解并不标准。

按照上面的算法得到:
8/11 = 1/2+1/5+1/37+1/4070
由此可见答案并不唯一。

为了通过这题,下面介绍第二个解题方法:
解题思路2:
【真分数分解为埃及分数】

 * 若真分数的分子a能整除分母b,则真分数经过化简就可以得到埃及分数,
 * 若真分数的分子不能整除分母,则可以从原来的分数中分解出一个分母为b/a+1的埃及分数。
 * 用这种方法将剩余部分反复分解,最后可得到结果。

C/C++的代码如下:

#include <iostream>
#include <cstring>
using namespace std;
int main(){
    string s;
	while(cin >> s){
		string s1, s2;
	int a = 0, b = 0, c = 0, r = 0;
        int n = s.length();
        int x = s.find('/');
        s1 = s.substr(0,x);
        s2 = s.substr(x+1);
        for(int i = 0; i < s1.length(); i++){
        	a = a * 10 + s1[i]-'0';
		}
		for(int i = 0; i < s2.length(); i++){
        	b = b * 10 + s2[i]-'0';
		} 
		while(a != 1){
			if(b % (a-1) == 0){
				cout << "1/" << b/(a-1) << "+";
				a = 1;
			}
			else{
				c = b/a + 1;
				cout << "1/" << c << "+" ;
				a = a*c - b;
				b = c * b;
				if(b%a == 0){
					b = b/a;
					a = 1;
				}
			}
		}
		cout << "1/" << b << endl;
	}
    return 0;
}

这个代码就可以通过……

此外:

我还看到一个用Java解题的代码不错(qaq不是我写的),附上链接:大佬的java解题代码及思路

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值