自幂数最大位39,遍历是不可能的。根据性质,自幂数和数的大小与各个位数上的幂次和有关。遍历数需要次,但如果是遍历各个位数上的幂次和呢,就是
了。
从0~9每个数字在这个数中都可能出现0~n次,就是。
那么,肯定有疑问了,和
以数字10为分阶线,前者十以内更小一点,可是我们连10位数都要跑好久,这样乍一看,还是要耗时好久,至少得个小半个小时。
所以这种遍历方法还有一个优势,就是剪枝。
1.每个数字的出现次数和等于n
2.一旦幂次和大于上限,continue
3.一旦幂次和(当前值+剩余次数*当前最大幂,有点难讲清楚,看代码吧)小于最小值,continue
如果还要更快一点,那就再来个记忆化搜索。
还有就是cout没法输出那么大的数,也不知道最大时多少,反正30位是不可能的。
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int aa[10],bb[10];
__int128 num[10];
__int128 max1,min1;
void print128(__int128 x)
{
if(x == 0) return ;
print128(x / 10);
putchar(x % 10 + '0');
}
void recursion(__int128 sum,int nowp,int less)
{
if(less<0) return;
if(nowp==0)
{
aa[0]=less;
less=0;
}
if(sum+less*num[nowp]<min1) return;
if(less==0)
{
__int128 sum1=sum;
for(int i=0;i<10;i++) bb[i]=aa[i];
while(sum1)
{
int ss=sum1%10;
if(bb[ss]<=0)
{
return;
}
bb[ss]--;sum1/=10;
}
print128(sum);cout<<" ";return;
}
for(int j=0;j<=less;j++)
{
aa[nowp]=j;
if(sum+j*num[nowp]>max1) break;
recursion(sum+j*num[nowp],nowp-1,less-j);
aa[nowp]=0;
}
}
int main()
{
for(int i=1;i<=30;i++)
{
memset(aa,0,sizeof(aa));
for(int j=0;j<10;j++)
{
num[j]=pow(j,i);
}
min1=pow(10,i-1);max1=10*min1-1;
cout<<i<<"位数:";
recursion(0,9,i);
cout<<endl;
}
}