高位水仙花数
本算法主要是采用化排列为组合的方法,减少冗余。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);
}