【 埃及分数 】【 IDA* 】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/violinlove/article/details/82825668

题面:

主要是理解思想,建议:代码还是自己写

主要有三点

1. 确定搜索层数

2. 适当剪枝(你会发现:emmm,常见的剪枝就可以满足啦)

3. 一些公式应该自己进行通分、推导

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define LL long long
#define MAXN 1000006

using namespace std;

inline int wread(){
    char c=getchar ();int flag=1,wans=0;
    while (c<'0'||c>'9'){if (c=='-') flag=-1;c=getchar ();}
    while (c>='0'&&c<='9'){wans=wans*10+c-'0';c=getchar ();}
    return wans*=flag;
}
int n,m;
int top=1;
int sav[MAXN],savt;
int pr[MAXN];

bool F;
LL gcd (LL a,LL b){
	if (!b)	return a;
	return gcd(b,a%b);
} 
//top 限制层数
//savt 保存的数组的编号
//F 判断是否成功
//St 最小的起点

 
void dfs (int ceng,int la,int U,int D){
//ceng:层数
//la:上一个所选择的分母 即1/la 
//U:总和的分子
//D:总和的分母
	if (ceng==top) {
		int nU(n*D-U*m),nD(m*D);
		if (nU<0 || nD <0)	return ;
		int gcdud(gcd(nU,nD));
		if (nU/gcdud==1){
			sav[ceng]=nD/gcdud;
			if (sav[ceng]<=la)	return ;
			if (sav[ceng] >= pr[ceng])	return ;
			F=true;
			for (int i=1;i<=ceng;++i){
				pr[i]=sav[i];
			}
		}
		return ;
	}
	int shen_c((top+1-ceng));
	double Lin;
	if (ceng==1)
		Lin=(m*shen_c*1.0)/(n*1.0);
	else 
		Lin=(m*D*shen_c*1.0) / ( n*D*1.0 - U*m*1.0 );
	int maxi=Lin;
	for (int i=la+1;i<=maxi;++i){
		if (ceng==1)	{
			sav[ceng]=i;
			dfs (ceng+1,i,1,i);
		}
		else {
			int nU=U*i+D,nD=D*i;
			int sam(gcd(nU,nD));
			sav[ceng]=i;
			dfs(ceng+1,i,nU/sam,nD/sam);			
		}
	}
	return ;
}

void solve (){
	memset (pr,0x3f3f3f3f,sizeof pr);
	int St=m/n;
	if (n*St!=m)	St++;
	while (true){
		++top;
		memset (sav,0,sizeof sav);
		F=false;
		dfs(1,St-1,0,0);
		if (F)	{
			for (int i=1;i<=top;++i){
				printf("%d ",pr[i]);
			}
			break;
		}
	}
	return ;
}

int main (){
	n=wread();m=wread();//	n/m
	if (n==1)	{
		printf("%d %d\n",n,m);
		return 0;
	}
	solve();	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/violinlove/article/details/82825668
IDA