蓝桥杯 2015校内选拔试题 第六题:1/a 的分数称为单位分数



形如: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);
	}
}












  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值