高位水仙花数算法

高位水仙花数

本算法主要是采用化排列为组合的方法,减少冗余。21位的测试时间为16s

 

#include<iostream>

#define N 21

using namespace std;

int power[10][30];
int rep[30];
int min(int a,int b)
{
    if(a<b) return a;
    return b;   
}
int max(int a,int b)
{
    if(a>b) return a;
    return b;   
}
void plus(int *num1,int *num2)//加法
{
     int i;
     int high=max(num1[0],num2[0]);
     /*****清零操作 本程序中更高位已确定是0,故可以省略
     int low=min(num1[0],num2[0]);
     for(i=low+1;i<=high;++i)
         if(num1[0]>num2[0])
            num2[i]=0;
         else num1[i]=0;
     num1[high+1]=0;
     num2[high+1]=0;*/
     int mov=0;
     for(i=1;i<=high;++i)
     {
                        
         int p=num1[i]+num2[i]+mov;
         mov=p/10;
         num1[i]=p%10;                   
     }  
     num1[0]=high; 
     if(mov)
     {
          num1[0]=high+1;
          num1[high+1]=mov;      
     }
}

void minus(int *num1,int *num2)//减法
{
     int i;
     for(i=num2[0]+1;i<=num1[0];++i)
        num2[i]=0;
     for(i=1;i<=num1[0];++i)
     {
        if(num1[i]<0||num1[i]<num2[i])
        {
             num1[i+1]--;
             num1[i]+=10;                             
        }               
        num1[i]-=num2[i];      
     }    
     for(i=num1[0];i>=1;--i)
        if(num1[i]) break;
     if(i==0)i=1;
     num1[0]=i;
}
void mul(int *num,int p)//乘法 ,p可以是两位数,
{
     int mov=0;
     int i;
     for(i=1;i<=num[0];++i)
     {
         int t=mov+num[i]*p;
         num[i]=t%10;
         mov=t/10;                     
     }    
     while(mov>0)
     {
          num[i++]=mov%10;
          num[0]++;
          mov/=10;     
     }
}

void print(int *num)
{
     for(int i=num[0];i;--i)
        cout<<num[i];
     cout<<endl;    
}

bool judge(int *count,int *num)//判断num是否为水仙花数,count用于存储各数字出现的频数
{
     int temp[10]={0};
     for(int i=1;i<=num[0];++i)
     {
         int p=num[i];
         temp[p]++;
         if(temp[p]>count[p])
            return false;       
     }    
     for(int i=0;i<10;++i)
        if(temp[i]<count[i])
           return false;
     return true;
}
void search(int p,int *count,int sum,int *num)//count用于存储各位数字的频数,sum用于累计count的总数,num用于保存各位数字高次方的和
{
     void plus(int *,int *);
     void minus(int *,int *);
     if(p==0)
     {
          count[p]=N-sum;
          if(judge(count,num))
             print(num);
          return ;       
     }    
     if(sum>=N)
     {
         for(int i=0;i<=p;++i)
             count[i]=0;
         if(judge(count,num))
            print(num);
         return ;         
     }
     if(p<=5&&sum>17) return ;//小数字出现频度过高
     if(p==9&&sum>6) return ;//9出现的频度过高
     if(p>=7&&sum>14) return ;//大数字出现的频度过高
     count[p]=0;
     search(p-1,count,sum,num);
     while(sum<=N)
     {
          count[p]++;
          sum++;
          plus(num,power[p]);
         
          if(num[0]>N) //当num明显越位时则排除其可能性 退出循环
              break;
          search(p-1,count,sum,num);         
     }
     //循环结束后,要恢复num的值
     for(int i=0;i<=power[p][0];++i)
             rep[i]=power[p][i];
     mul(rep,count[p]);
     minus(num,rep);
}

int main()
{
    int num[30]={0},count[11];
    num[0]=1;
    num[1]=0;
    for(int i=0;i<10;++i)
       count[i]=0;
    power[0][0]=1;power[0][1]=0;
    for(int i=1;i<10;++i)
    {
        power[i][0]=1;
        power[i][1]=1;
        for(int j=1;j<=N;++j)
            mul(power[i],i);       
    }
    search(9,count,0,num);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值