[题解]「一本通 1.3 练习 1」埃及分数

埃及分数题目链接

这道题比较经典。

算法:迭代加深+IDA*

优化:

1.迭代加深

2.确定从小到大的搜索顺序

3.确定搜索上下界

(1)以i为分母的数字不能大于a/b.

(2)如果后面的数字都以i为分母仍然<=a/b,退出。

细节:

(1)在通分过程中会爆int。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll unsigned long long 
#define R register
using namespace std;
const int N=1e5+5;
ll ans_a,ans_b,ans[N],lin[N],k,flag,vis[N];
inline ll gcd(R ll a,R ll b){
    if(b==0)return a;
    return gcd(b,a%b);
}
inline void dfs(R ll x,R ll a,R ll b,ll lst)//正在填第几个   
{
    if(x==k){
        if(b%a==0)
        {
            flag=1;
            ans[k]=b/a;
            if(ans[k]<lin[k])
            for(R ll i=1;i<=k;i++)
            lin[i]=ans[i];
        }
        return;
    }
    for(R ll i=lst+1;i;i++)
    {
        if((k-x+1)*b<=a*i)break;
        if(i*a<b)continue;
        R ll zi=i*a-b;
        R ll mu=i*b;
        R ll g=gcd(zi,mu);
        ans[x]=i;
        dfs(x+1,zi/g,mu/g,i);
        ans[x]=0;
    }
}
int main(){
    scanf("%lld%lld",&ans_a,&ans_b);cn
    k=0;
      k=gcd(ans_a,ans_b);
      ans_a/=k;   ans_b/=k;
      k=0;
      memset(lin,127,sizeof(lin));
      while(!flag)
      {
          k++;
          dfs(1,ans_a,ans_b,0);
      }
      for(R ll i=1;i<=k;i++)
      printf("%lld ",lin[i]);
      return 0;
}
//迭代加深
//上下界剪枝

猜你喜欢

转载自www.cnblogs.com/sky-zxz/p/9898345.html
今日推荐