SCAU 计算智能 暴力美学(三)

题三:18444 分数拆分

Description

输入正整数k(k<=1000),将1/k变为不少于2项,但不多于3项的1/(xi)之和,xi为正整数,且i表示序号

注:请使用long long

输入格式

多case,一行一个整数k

最后一行是0

输出格式

对每一个case,按等式最右边一项分母,由小到大排序输出满足条件的等式,最右边一项分母相同,则按最右边第二项,依次类推

每一个case完成后,输出一个空行(没有满足的等式时,也要输出该空行)

输入样例

2
3
4
0

输出样例

1/2=1/6+1/3
1/2=1/42+1/7+1/3
1/2=1/24+1/8+1/3
1/2=1/18+1/9+1/3
1/2=1/15+1/10+1/3
1/2=1/12+1/12+1/3
1/2=1/4+1/4
1/2=1/20+1/5+1/4
1/2=1/12+1/6+1/4
1/2=1/8+1/8+1/4
1/2=1/10+1/5+1/5
1/2=1/6+1/6+1/6

1/3=1/12+1/4
1/3=1/156+1/13+1/4
1/3=1/84+1/14+1/4
1/3=1/60+1/15+1/4
1/3=1/48+1/16+1/4
1/3=1/36+1/18+1/4
1/3=1/30+1/20+1/4
1/3=1/28+1/21+1/4
1/3=1/24+1/24+1/4
1/3=1/120+1/8+1/5
1/3=1/45+1/9+1/5
1/3=1/30+1/10+1/5
1/3=1/20+1/12+1/5
1/3=1/15+1/15+1/5
1/3=1/6+1/6
1/3=1/42+1/7+1/6
1/3=1/24+1/8+1/6
1/3=1/18+1/9+1/6
1/3=1/15+1/10+1/6
1/3=1/12+1/12+1/6
1/3=1/21+1/7+1/7
1/3=1/12+1/8+1/8
1/3=1/9+1/9+1/9

1/4=1/20+1/5
1/4=1/420+1/21+1/5
1/4=1/220+1/22+1/5
1/4=1/120+1/24+1/5
1/4=1/100+1/25+1/5
1/4=1/70+1/28+1/5
1/4=1/60+1/30+1/5
1/4=1/45+1/36+1/5
1/4=1/40+1/40+1/5
1/4=1/12+1/6
1/4=1/156+1/13+1/6
1/4=1/84+1/14+1/6
1/4=1/60+1/15+1/6
1/4=1/48+1/16+1/6
1/4=1/36+1/18+1/6
1/4=1/30+1/20+1/6
1/4=1/28+1/21+1/6
1/4=1/24+1/24+1/6
1/4=1/140+1/10+1/7
1/4=1/42+1/12+1/7
1/4=1/28+1/14+1/7
1/4=1/8+1/8
1/4=1/72+1/9+1/8
1/4=1/40+1/10+1/8
1/4=1/24+1/12+1/8
1/4=1/16+1/16+1/8
1/4=1/36+1/9+1/9
1/4=1/18+1/12+1/9
1/4=1/20+1/10+1/10
1/4=1/15+1/12+1/10
1/4=1/12+1/12+1/12

思路:

显然这是一个暴力枚举的问题,对于枚举而言,私以为大原则有一,关键有三。

大原则,简化问题,简化时间复杂度。

关键一:确定枚举对象

关键二:确定枚举范围

关键三:确定枚举条件,限制条件

最后再处理枚举过程中的细节问题,比如,乘法溢出问题,除法中的数据丢失问题,等等。

 

对于这道题,我们先简化分析他,对于两个的情况,1/x+1/y=1/ p。

那么我们就很轻松的可以想到,以其中一项为枚举对象, 寻找枚举的范围,来实现枚举。

接下来就是对于枚举对象的选择问题,从而寻早枚举的范围,设定x>=y>p;

我们通过放大原式,可以得到, 1/y+1/y >= 1/x+1/y = 1/p;即,2/y>=1/p;

所以,可得y的枚举范围[1,2p];那么,反过来,缩小原式是不可以实现找到枚举范围的。

最后再限制枚举的条件,同样,我们分析并转化原式1/x=1/p-1/y;即,x=p*y/(y-p);

那么,据题目要求,我们需要判定,x=p*y/(y-p)是不是整数,且y<=2*p。

这里有一个方法,对于除法柿子,我们只需要判断p*y%(y-p)?=0,即判断p*y是否整除(y-p);

 

那么三个项的情况,其实就可以转化为两个项的情况。对于,1 /x+1/y+1/z=1 /k;转化为->1/x+1/y= 1/k-1/z =1/p;同理我们设定,x>=y>=z>k

那么我们的枚举对象有两个,

第一个,先枚举z,利用已知的k,求得不同的p,判断,求出两个项的结果;

第二个,枚举y,利用求得的p,得到不同的x,判断,求出三个项的结果。

很自然的想到,我们的枚举范围是什么,同理,我们放大原式,得到z的范围,[1,3*k];y的范围[1,2*p];

对于第一个枚举对象,我们可以看作,对1/p+1/z=1/k的枚举,同上,我们需要判断,p=k*z/(z-k)是不是整数,且z<=2*k;

 对于第二个枚举对象,我们看作z已经确定,1/x+1/y=1/p的枚举,同上我们需要判断,x=p*y/(y-p)是不是整数,且 z<=y<=2*p;

理论上到这里我们就写完了,但是显而易见的我们需要处理一些枚举过程中的细节问题,

1.题目提示我们使用long long

2.其中包含了大量的除法计算,会存在数据丢失(四舍五入)的问题。题中,1/p=1/k-1/z 即 p=k*z/(z-k) 的结果不一定是一个整数。会导致第二个枚举的计算结果出现错误,还有枚举范围的偏差。

 对于数据丢失导致计算错误的问题,这里处理方式为,分离k*z/(z-k)的分子和分母。记t1=k*z,t2=z-k;

很简单的数学转换,将p*y%(y-p)?=0 转化为-> y * t1 % (y * t2 - t1) == 0;   x=p*y/(y-p) 转化为-> x = y * t1 / (y * t2 - t1);

对于数据丢失导致的y枚举范围变化问题,我们可以将y的范围变为[1,2*p+1]解决。

简单证明:已知,p=k*z/(z-k)的结果小数位数值<0.5为出现数据丢失。

那么p其实一共有两种情况,小数位 <0.5 或者 小数位>=0.5;

1.设p=3.4,计算机中显示结果为3;令p+=0.5,p=3.9,计算机显示结果为4;防止丢失.

2.设p=3.6,计算机中显示结果为4;令p+=0.5,p=4.1,计算机显示结果为4;防止丢失.

那么y的范围可以写出[1,2*(p+0.5)];

综上,分析结束,我们就可以写出如下代码。

#include<iostream>
using namespace std;
long long k ;
void show(long long x,long long y,long long z) {
	cout << "1/" << k << "=" << "1/" << x << "+" << "1/" << y << "+" << "1/" << z << endl;
}
void _show(long long y,long long z) {
	cout << "1/" << k << "=" << "1/" << y << "+" << "1/" << z << endl;

}
int main() {

	cin >> k;
	while (k) {
		long long x = 0, y = 0, z = 0, p = 0;;
		for (z = k + 1; z <= 3 * k; z++) {

			p = k * z / (z - k);
			if (z <= 2 * k && k * z % (z - k) == 0) { y = k * z / (z - k); _show(y, z); }
            //子母分离
			long long t1 = k * z;
			long long t2 = z - k;
			for (y = p + 1; y <= 2 * p + 1; y++) {
				if (y >= z && y * t1 % (y * t2 - t1) == 0) {
					x = y * t1 / (y * t2 - t1);
					//x = p * y / (y - p);
					show(x, y, z);
				}

			}
		}
		cout << endl;
		cin >> k;
	}
	

}

写得较急,如有错误,请不吝赐教。

 

 

 


 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值