埃及数最短分解

111 阅读1分钟

题意

给定一个真分数ab\frac{a}{b} 其中 a < b ,求该真分数的最短埃及数分解。

解法

考虑贪心做法 ,试着找一个距离ab\frac{a}{b}最近的埃及数,即不大于ab\frac{a}{b}的最大埃及数k,减去 k , 对剩下的 abt\frac{a}{b} - t 进行同理的分解,即可得到最短的埃及数分解。

如何求出满足限制的最大埃及数 ?

  • 给出结论: k=abk = \lfloor \frac{a}{b} \rfloor

  • 证明

    考虑:将 b 表示成 ak+ca * k + c , 其中 c<kc < k

    b=ak+cb = a * k + c 对两边都除以 a

    则有 ba=k+ca\frac{b}{a} = k + \frac{c}{a} , 其中 cb<1\frac{c}{b} < 1

    若上式的a0,b0a \not= 0 , b \not= 0 , 那么考虑将上式取倒数

    ab=1k+ca\frac{a}{b} = \frac{1}{k + \frac{c}{a}}

    因为 cb>1\frac{c}{b} > 1 , 那么可得

    ab=1k+ca>1k+1\frac{a}{b} = \frac{1}{k + \frac{c}{a}} > \frac{1}{k + 1}

    1k+1\frac{1}{k + 1} 一定是该数的最大埃及数!

    由原式 b=ak+cb = a * k + c 可得 k = ba\lfloor \frac{b}{a} \rfloor

为了将过程表述完整下面给出完整步骤:

  1. 求出根据公式求出k + 1
  2. ab1k+1\frac{a}{b} - \frac{1}{k + 1} , 求出新的分子分母通分,重复1、2步。
  3. a = 1 时 即可不再重复以上操作,输出最后的结果即可

参考代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>

void solved(){

	std::string num;
	std::cin >> num;

	int a = 0 , i , b = 0;

	for (i = 0; num[i] != '/'; i ++ )
		a = a * 10 + (num[i] - '0');

	i ++;			// 移到数字位

	for (;i < int(num.size()); i ++ )
		b = b * 10 + (num[i] - '0');


	std::cout << a << '/' << b << " = " ;

	while(a > 1){
		int k = b / a + 1;
			
		std::cout << 1 << "/" << k << " + ";

		a = a * k - b;
		b = b * k;

		int r = std::__gcd(a , b);
		if(r > 1){						// 约分 , 两个数不互质
			a /= r;
			b /= r;
		}
	}

	std::cout << a << "/" << b << '\n';
}


int main(){

	std::ios::sync_with_stdio(0);
	std::cin.tie(0);
	std::cout.tie(0);

	solved();

	return 0;
}