埃及数字(迭代深搜)

题目描述 Description

在古埃及,人们使用单位分数的和(形如1/a的, a是自然数)表示一切有理数。 如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的。 对于一个分数a/b,表示方法有很多种,但是哪种最好呢? 首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越 好。 如: 19/45=1/3 + 1/12 + 1/180 19/45=1/3 + 1/15 + 1/45 19/45=1/3 + 1/18 + 1/30, 19/45=1/4 + 1/6 + 1/180 19/45=1/5 + 1/6 + 1/18. 最好的是最后一种,因为1/18比1/180,1/45,1/30,1/180都大。 给出a,b(0<a<b<1000),编程计算最好的表达方式。

输入描述 Input Description

a b

输出描述 Output Description

若干个数,自小到大排列,依次是单位分数的分母。

样例输入 Sample Input

19 45

样例输出 Sample Output

5 6 18

一个迭代加深模版题,然而我默默地打了一个晚上。。

主要注意剪枝和数据要开longlong,因为没开longlong在codves上最后一个点爆了

#include<bits/stdc++.h>
#define ll long long
using namespace std;

ll a,b,maxd,ans[1010],tmp[1010];

ll gcd(ll x,ll y){
    return y?gcd(y,x%y):x;
}

bool dfs(ll a,ll b,ll step){
    if(step==maxd){
      if(a==1){
          if(b>tmp[step-1]){
              tmp[step]=b;
            if(tmp[step]<ans[step]){
                for(int i=1;i<=step;i++) ans[i]=tmp[i];
            }
          }
          return 1;
      }
      else return 0; 
    }
    if(a/(b*(maxd-step+1))>ans[maxd]) return 0;
    bool ok=0;
    for(int i=max(tmp[step-1]+1,b/a);i<=b*(maxd-step+1)/a;i++){
        if(b>a*i) continue;
        tmp[step]=i;
        ll c=gcd(a*i-b,b*i);
        if(dfs((a*i-b)/c,(b*i)/c,step+1)) ok=1;
    }
    if(!ok)return 0;return 1;
}

int main(){
    scanf("%lld%lld",&a,&b);
    ll c=gcd(a,b);
    a/=c;b/=c;
    if(a==1){
        printf("%lld",b);
        return 0;
    }
    for(int i=1;i<=1000;i++) ans[i]=10000000;
    for(maxd=2;;maxd++){
        memset(tmp,0,sizeof(tmp));tmp[0]=1;
        if(dfs(a,b,1)){
            for(int i=1;i<=maxd;i++) printf("%d ",ans[i]);return 0;
        }
    }
}