单位分数

/**
 * 
 * 
形如: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

 */

	public static void main(String[] args)
	{
		Scanner input = new Scanner(System.in);
		int n = input.nextInt();
		List<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
		dfs(n, 0, 0.0,res,new ArrayList<Integer>());
		
		//遍历集合输出
		for(int i=0;i<res.size();i++){
			for(int j=0;j<res.get(i).size();j++){
				System.out.print("1/"+res.get(i).get(j)+"\t");
			}
			System.out.println();
		}
	}
	
	public static boolean dfs(int n,int cur,double sum,List<ArrayList<Integer>> res,List<Integer> now)
	{
		//cur:当前项
		//如果当前总和已经大于1.0 或者 当前刚好为n项但是其值不等于1.0则返回false(因为可能存在精度的问题,1.0不应该直接写等号,应该用1.0减去一个足够小的数字,比如1e-8)
		if(sum > 1.0 || (cur==n) && Math.abs(sum-1.0)>=1e-8){
			return false;
		}
		//如果满足就可以将这组结果存入res并返回true
		else if(cur==n && Math.abs(sum-1.0)<1e-8){
			res.add(new ArrayList<Integer>(now));
			return true;
		}
		
		//因为每个数字(分母)是递增的,所以没必要每次都从1 开始。判断如果当前结果为空则从1开始,否则从上次得到的那值+1开始。 遍历每个数字
		int i = now.isEmpty()?1:now.get(now.size()-1)+1;
		for(;i<30;i++){
			//因为保证没有重复的数字,要加一个if(now.indexOf(i) != -1)判断是否存在
			if(now.indexOf(i) != -1) continue;
			now.add(i);
			if(dfs(n,cur+1,sum+1.0/(i*1.0),res,now)){
				//假设 2 3 9 18 四个数字是ok的,删除最后一个18
				now.remove(now.size()-1);
				//既然 2 3 9 18 可以构成1,那么 2 3 9 19 是不可能的,所以返回false	
				return false;
			}
			//回溯,移除i,进行下一轮查找
			now.remove(now.size()-1);
		}
		
		return false;
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值