埃及分数

迭代深搜 
1.全场打long long
2.搜索时,最小的数从大往小的搜
其他的从小往大搜
3.限制开头:并不是每次都要从1开始遍历分母,假设现在要分解a/b,那么分母b/a就是起点,因为b/a的分数太大,起始点已经超过了a/b,没有什么意义:1/(b/a)=a/b ,假设起点s<b/a,那么显而易见,起点的分数已经比我们要的总和(a/b)大了。 
4.比较简单的限制结尾可以这样看:如果我已经找到分母k了,而现在要分解得分数是a/b,现在还要找m个单位分数,那么可以想象:有可能 m * ( 1/k ) 还小于a/b,也就是说就算全是1/k,我凑够m个,也达不到a/b,那么说明前面的分配方案肯定有无,直接可以return了。加上这个剪枝已经可以得到答案了,只是时间有点慢罢了。 
5。现在我们假设终点为t,还要找m个单位分数,现在的分数剩下a/b,那么很容易有m * (1/t) <= a / b  ,也就是说我如果m个都用最小的,肯定小于等于a/b。(等于号就是说有可能m=1,我可能直接终点就是答案,如果m>1,那么终点肯定也不可能选到,假设选了(后面还要选(m-1)个,肯定凑不够)这样子,由上面的式子,经过变换,可以得到 t >= m*b/a ,也就是说终点为m*b/a。 
a<b<1000

#include<bits/stdc++.h>
using namespace std;
long long n,m,h,ji[11],jians[11];
inline int g(long long a,long long b)
{
  int c=a%b;
  while(b)
  {
    c=a%b;
    a=b;b=c;
  }
  return a;
}
inline bool cha(long long a,long long b,int shen)
{
  if(a==0)
  return 1;
  if(a==1&&shen==1)
  {
    ji[shen]=b;return 1;
  }
  if(shen!=1&&shen!=2)
  {
    bool da=0;
    for(int i=b/a+1;i<=b/a*shen;i++)
    {
      ji[shen]=i;
      if(shen*b>=i*a&&ji[shen]>ji[shen+1])
      {
        int gcd=g(a*i-b,b*i);
        if(cha((a*i-b)/gcd,b*i/gcd,shen-1)==1)
        {
          da=1;
          if(shen==2&&(jians[1]==0||jians[1]>ji[1]))
          for(int j=1;j<=h;j++)
            jians[j]=ji[j];
        }
      }
   }
   return da;
  }
  if(shen==1||shen==2)
  {
    bool da=0;
    for(int i=b/a*shen;i>=b/a+1;i--)
    {
      ji[shen]=i;
      if(shen*b>=i*a&&ji[shen]>ji[shen+1])
      {
        int gcd=g(a*i-b,b*i);
        if(cha((a*i-b)/gcd,b*i/gcd,shen-1)==1)
        {
          da=1;
          if(shen==2&&(jians[1]==0||jians[1]>ji[1]))
          for(int j=1;j<=h;j++)
            jians[j]=ji[j];
        }
      }
    }
  return da;
  }
}
int main()
{
  cin>>n>>m;
  h=1;
  while(cha(n,m,h)==0)
  {
    h++;
  }
  for(int i=h;i>=1;i--)
    cout<<jians[i]<<" ";
}

//低估这道题了,十点半没刷出来

posted @ 2019-05-19 18:49  fanhao110  阅读(455)  评论(0编辑  收藏  举报