数字排列问题

需求:
  求第1500个只有2,3,5因子的数           
  数是从小到大排列           
  第一个数是1,1=2^0*3^0*5^0           
  


  //execute   result:   
  //pos:1500   ==>   ans:(2^17*3^8*5^0)   
  //Calculate   time   estimate   <   172/1000,000   s   
  //Press   any   key   to   continue   
  //any   other   infomation:   http://www.ohyee.net   
  #include   <stdio.h>
  #include   <math.h>
  #include   <windows.h>


  const   int   factor[3]={2,3,5};
  int   nPos     =   1500;


  double   Cartan(double   a,   double   b,   double   c)
  {
          double   t1;
          t1   =   pow(36.*b*a-108.*c-8.*a*a*a+12*sqrt(12.*b*b*b-3.*b*b*a*a-54.*b*a*c+81.*c*c+12.*c*a*a*++a),   1./3.);
          return   (t1-(12.*b-4.*a*a)/t1-2.*a)/6.;
  }


  int   main()
  {
          double   fWei[3],   fmin,   fmin1,   fTmp,   fTmp2;
          double   a,b,c,t;
          int   cnt,   n,   i,   j,   k,   i0,   j0,   k0,   i1,j1,k1;
          int   repeat;
          unsigned   long   dTic;


          for(i=0;   i<3;   i++)
          {
                  fWei[i]   =   log(factor[i]);
          }


          n   =   nPos;
          dTic   =   GetTickCount();
          for(repeat=1;   repeat<1000;   repeat++,   n   =   nPos)
          do
          {
                  cnt   =   0;


                  a=fWei[0]+fWei[1]+fWei[2];
                  b=fWei[0]*fWei[1]+fWei[0]*fWei[2]+fWei[1]*fWei[2];
                  c=(1.-3.*(n+.5))*fWei[0]*fWei[1]*fWei[2];


                  t   =   Cartan(a,b,c);
                  a   =   t/fWei[0];


                  fmin1   =   fmin   =   n*3+10.;
                  for(i=0;   i<=a;   i++)
                  {
                          fTmp   =   t-i*fWei[0];
                          b   =   fTmp/fWei[1];
                          for(j=0;   j<=b;   j++)
                          {
                                  fTmp2   =   fTmp   -   j*fWei[1];
                                  k   =   (int)(fTmp2/fWei[2]);
                                  cnt   +=   k+1;
                                  fTmp2   =   fTmp2   -   k*fWei[2];


                                  if(fmin   >   fTmp2)
                                  {
                                          fmin   =   fTmp2;
                                          i0=i;j0=j;k0=k;
                                  }
                                  else   if(fmin1   >   fTmp2)
                                  {
                                          fmin1   =   fTmp2;
                                          i1=i;j1=j;k1=k;
                                  }
                          }
                  }


                  if(cnt<nPos)
                  {
                          n   +=   (nPos-cnt)*1.3;
                          continue;
                  }
                  if(cnt==nPos)
                  {
                          break;
                  }
                  else   if(cnt==nPos+1)
                  {
                          i0=i1;j0=j1;k0=k1;
                          break;
                  }
                  else
                  {
                          printf("sorry,   can't   find:(");
                          return   -1;
                  }
          }   while(1);


          dTic   =   GetTickCount()-dTic;


          printf("pos:%d   ==>   ans:(2^%d*3^%d*5^%d)\n",   nPos,   i0,j0,k0);
          printf("Calculate   time   estimate   <   %d/1000,000   s\n",   dTic);


          return   0;
  }




 




  ax+by+cz < L
  不失一般性,假设 0<a<b<c;x,y,z属于R;
  其中的满足表达式的x,y,z个数可以认为A平面ax+by+cz=L,x=0,y=0,z=0四个平面包围的体积是
  同步变化的。所以就有方程   (x0+1)(y0+1)(z0+1)=P*6,   其中x0=L/a,y0=L/b,z0=L/c.   而P则是
  体积值,也就是要求的目标数值(题目中为1500)。将上面两式联合求解,就可以得到x0,y0,z0.求解
  该方程使用了标准的一元三次方程求解公式:卡尔丹公式
  知道x0,y0,z0就可以知道最接近这个A平面的点(X,Y,Z)的具体数值了,我这用的是遍历,而这个点就是
  最终所求的三个幂指数数值。
  实际上我并没有用真正的体积公式,而是把P*6改成了P*3,然后根据误差把P放大,逐步贴近真实数值。
  这种做法到底能有多大好处,我也没有进行严格推导,只是有一点可以肯定的,不用开过多的空间来
  存储中间变量和做过多的排序了。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值