形如:1/a 的分数称为单位分数。
可以把1分解为若干个互不相同的单位分数之和。
例如:
1 = 1/2 + 1/3 + 1/9 + 1/18
1 = 1/2 + 1/3 + 1/10 + 1/15
1 = 1/3 + 1/5 + 1/7 + 1/9 + 1/11 + 1/15 + 1/35 + 1/45 + 1/231
等等,类似这样的分解无穷无尽。
我们增加一个约束条件:最大的分母必须不超过30
请你求出分解为n项时的所有不同分解法。
数据格式要求:
输入一个整数n,表示要分解为n项(n<12)
输出分解后的单位分数项,中间用一个空格分开。
每种分解法占用一行,行间的顺序按照分母从小到大排序。
例如,
输入:
4
程序应该输出:
1/2 1/3 1/8 1/24
1/2 1/3 1/9 1/18
1/2 1/3 1/10 1/15
1/2 1/4 1/5 1/20
1/2 1/4 1/6 1/12
再例如,
输入:
5
程序应该输出:
1/2 1/3 1/12 1/21 1/28
1/2 1/4 1/6 1/21 1/28
1/2 1/4 1/7 1/14 1/28
1/2 1/4 1/8 1/12 1/24
1/2 1/4 1/9 1/12 1/18
1/2 1/4 1/10 1/12 1/15
1/2 1/5 1/6 1/12 1/20
1/3 1/4 1/5 1/6 1/20
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 2000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
======================================================
思路:
单位分数(互不相同) 分母必须不超过30 求出分解为n项时的所有不同分解法 n项(n<12)
每种分解法占用一行,行间的顺序按照分母从小到大排序。
---------------------------------------错误思路----------------------------------------------------
1.给第一个数1/n=2
2.给第二个数1/n+1,
3.一直给到第n个数,凑成最大的组合。。。
---------------------------------------------------------------------------------------------------
好像规律抓不到,进行百度。。。
百度都是用C解决的,里面提到了递归,没有学过递归,现在对递归进行学习。
递归是什么??
递归就是不断调用函数本身来解决那些繁杂的问题(问题不断推给上层处理)
---------------------------------------错误思路----------------------------------------------------
学习了递归之后发现它有一个规律,需要最初始的值:所以算出我们符合的形式分母最小的值
1=1/2+1/3+1/6;
然后我们再依次以else延伸其他的情况并打印出来。(延伸到30为止)
延伸方式:最后一个分母加1,然后添加一个分数(分母大于最后一个分母)
一直到12个分母就停止!!!
现在有个问题就是,1/3能不能用其他分母代替,只是到1/12够吗??
为了绕过这个问题,我想到可以从最大的分母一直加到最小,加到为1为止
然后最小的那个更小一位,从小一直加到大
因为之后会不会刚好等于1也是问题,所以这个方法不成立!!(不过对它的递归好像又有一点理解)
---------------------------------------------------------------------------------------------------
我将对问题进行再一步询问和百度。。。
==========================================
想到用递归来分析思路:
从1/2开始,一个一个往下加,加到一样,就打印出来
加到超过,最大那个往后一位,再一个一个往下加
如果最大那个到底了,或者往下加的数到底了
第一个往下加,然后执行上边步骤,一直到第一个指标为29为止
==================================================================
错看题目,以为是打印全部,用递归做出来的超难还错的程序:
package com.aiqiongdiao;
public class Test {
public static void g(double huan[],double shu[],double fenzi,double fenmu,int i,int k,int j){
//涉及到小数的用double, deshu为分子的值
double deshu=(shu[i]*fenzi)-fenmu;
fenmu=fenmu*shu[i];
huan[k]=shu[i];
if(deshu>0){
if(i==30){
g(huan,shu,1,1,j+2,0,j+1);
}
if(j==29){
return;
}
g(huan,shu,deshu,fenmu,i+1,k+1,j);
}
if(deshu==0){
for(int a=0;a<=k;a++){
System.out.print(huan[a]+" ");
}
System.out.println();
g(huan,shu,fenzi,fenmu/shu[i],i+1,k,j);
if(i==30){
g(huan,shu,1,1,j+2,0,j+1);
}
if(j==29){
return;
}
}
if(deshu<0){
if(i==30){
g(huan,shu,1,1,j+2,0,j+1);
}
if(j==29){
return;
}
g(huan,shu,fenzi,fenmu/shu[i],i+1,k,j);
}
}
public static void main(String[] args) {
double huan[]=new double[100]; //缓存
double shu[]=new double[31]; //数值
for(int i=1;i<=30;i++){
shu[i]=(double)i;
}
double fenzi=1,fenmu=1;
int i=2,k=0,j=1; //数组指针
g(huan,shu,fenzi,fenmu,i,k,j);
}
}
==========================================
调整状态,重新编写这个程序
题目要求:
输入限定长度大小,打印该长度所有情况
1 = 1/2 + 1/3 + 1/9 + 1/18
1 = 1/2 + 1/3 + 1/10 + 1/15
1 = 1/3 + 1/5 + 1/7 + 1/9 + 1/11 + 1/15 + 1/35 + 1/45 + 1/231
百度告诉我这是一道深度优化的问题,刚刚地底寻宝的题目也是深度优化的题,
没办法,只好先好好了解深度优化,才能处理这一领域的问题。
网上代码C语言:
void dfs(int cur, // 当前需要查找的分式
int s, // 分母的最小值
long long fz, // 剩余未分配部分大小的分子
long long fm) // 剩余未分配部分大小的分母
{
// 如果需要查找最后一个分式
if (cur == n)
{
// 如果分母不能被分子整除,则最后一个分式无法构成
if (fm % fz)
return; // 从搜索中退回
// 最后一个分式的分母
a[cur] = fm / fz;
// 如果最后一个分式的分母大于30,从搜索中返回
if (a[n] > 30)
return; // 从搜索中退回
// 把所有的分式打印出来
for (int i = 0; i < n; i++)
printf("1/%d ", (int)a[i]);
printf("1/%d\n", (int)a[n]);
return; // 从搜索中退回
}
// 计算下一个分母的最小值
s = (int)max(s * 1LL, fm / fz + 1);
int i;
long long A, B, Gcd;
// 枚举所有可能的下一个分母
for (i = s;; i++)
{
// 假设后面所有的分式全部的分母都是 i,也不能够使得总和达到 fz / fm
if (i * fz >= fm * (n - cur + 1))
break; // 不再枚举更大的分母
// 设定当前分式的分母为 i
a[cur] = i;
// 剩余分数的分母
B = fm*i;
// 剩余分数的分子
A = fz*i - fm;
// 求最大公约数
Gcd = gcd(A, B);
// 深搜,求下一个分式,而且最小分母是 i + 1,剩余分数的分子分母都约分
dfs(cur + 1, i + 1, A / Gcd, B / Gcd);
}
return;
}
根据暴力破解+递归思想,演化出for数量可变的递归,加上类型筛选~
代码实现:
package com.aiqiongdiao;
import java.util.Scanner;
class Main
{
public static void f(int num,int a[],int k){
if(num==k){
g(a); //判断为1
return; //跳出此次函数
}
for(int i=2;i<30;i++){
a[k]=i;
f(num,a,k+1);
}
}
public static void g(int a[]){
int sum=1;
int sum1=1;
int he=0;
//筛选等于,后面大于前面的数
for(int k=0;k<a.length;k++){
for(int l=k+1;l<a.length ;l++){
if(a[k]>=a[l]){
return;
}
}
}
for(int i=0;i<a.length;i++){
sum=sum*a[i];
for(int j=0;j<a.length;j++){
if(i==j){
continue;
}
sum1=sum1*a[j]; //单轮积需要n次
}
he=he+sum1;
sum1=1; //sum1需要清0
}
if(sum==he){
print(a);
}
else{
return;
}
}
public static void print(int a[]){
for(int i=0;i<a.length;i++){
if(i==a.length-1){
System.out.println("1/"+a[i]);
}
else{
System.out.print("1/"+a[i]+"+");
}
}
System.out.println();
}
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int num=input.nextInt();
int a[]=new int[num];
int k=0;
f(num,a,k);
}
}