迭代加深搜索(埃及分数)

       埃及分数是指分子是1的分数,也叫单位分数。古代埃及人在进行分数运算时。只使用分子是1的分数。因此这种分数也叫做埃及分数,或者叫单分子分数。

       给定一个分数,如19/45,我们可以把它表示为1/2 + 1/12+1/180,也可以表示为1/5+1/6+1/18,哪种最好呢?首先,加数少的比加数多的好,埃及分数问题即把一个真分数表示为最少的埃及分数之和的形式,表示为最少的埃及分数之和要求其末尾的埃及分数分母尽可能达到最小,即埃及分数尽可能大。其次,加数个数相同时,最小的分数越大越好。

设输入为a/b,b/a所得整数部分为c,余数部分为d,则

b=a*c+d

等式两边同除a得:

b/a=c+d/a

由于d小于a,所以d/a<1,放缩得:

b/a=c+d/a<c+1

两边倒数得:

a/b>1/(c+1)

设e等于c+1,1/e为当前最大埃及分数

a/b-1/e=(a*e-b)/b*e

以上可知一个真分数减去其最大埃及分数后a变成a*e-b,b变成b*e,得到dfs参数变化规律,下面是代码:

import java.util.Arrays;
import java.util.Scanner;
//a/b c为b/a所得整数部分 d 为其余数部分
/*b=a*c+d
*b/a=c+d/a
*b/a=c+d/a<c+1
*a/b>1/(c+1)
*设e为c+1
*a/b-1/e=a*e-b/b*e
*由此可得一个真分数减去其最大埃及分数等于(a*e-b)/b*e
/* 埃及分数问题:
 * 迭代加深搜索 从小到大枚举迭代深度上限 
 */
public class EgypFrac {
static final int MAX = 1000;//最大迭代深度
public static int a,b;
public static int maxd=1;
public static int mind=1;
public static int []ans=new int[1000];//保存答案的分母
public static int []den=new int[1000];//临时保存分数的分母
public static int gcd(int a,int b)//辗转相除返回最大公约数
{
	return b==0 ? a :gcd(b,a%b);
}
public static int Delimit(int x,int y){                   //确定分母的下界   
    for (int i=2;;i++){                 //即:1/i <= x/y   
        if (y<=x*i){  
            return i;  
        }  
    }  
}  
public static boolean Adjust(int a)
{
	if(ans[a]==-1) return true;
	if(ans[a]<den[a]) return false;
	if(ans[a]>den[a]) return true;
	for(int index=1;index<a;index++)
	{
		if(ans[index]==-1) return true;
		if(ans[index]<den[index]) return false;
		if(ans[index]>den[index]) return true;
	}
	return false;
}
public static boolean Iddfs(int d,int min_den,int x,int y)
{
	if(d==maxd) {//到达多项式数目
		if(y%x!=0) return false;//不是单位分数
		den[d]=y/x;
	  if(Adjust(d)) {
		for(int index=1;index<=d;index++)
		{
			ans[index]=den[index];
		}
	  }
	return true;
}
	min_den=Math.max(min_den,Delimit(x,y));
	boolean flag=false;
	for(int e=min_den;;e++)
	{
		if(y*(maxd-d+1)<=e*x)
			break;
		den[d]=e;
		//一个真分数减去一个最大埃及分数之后
		//原来的a 变成了,a * e - b,原来的b变成了 b * e
		int x1=x*e-y;
		int y1=y*e;
		int g=gcd(x1,y1);//得到公约数
		if(Iddfs(d+1,e+1,x1/g,y1/g)) {//deep 加深
			flag=true;
		}
	}
	return flag;
}
public static void main(String[] args)
{
	Scanner sc=new Scanner(System.in);
	a=sc.nextInt();
	b=sc.nextInt();
	if(b%a==0) {
		System.out.print(a+"/"+b);
	}
	else {
	mind=Delimit(a, b);
	while(maxd!=0)
	{
		maxd++;//多项数深度
		Arrays.fill(ans, -1);
		if(Iddfs(1,mind,a,b)) {
			break;
		}
	}
	int index;
	for(index=1;index<maxd;index++) {
		System.out.print("1/"+ans[index]+"+");
	}
	System.out.print("1/"+ans[index]);
	}
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值