21位水仙花数

哈喽沃的 2011-04-28 08:06:41
遇到一道题,要求在三分钟内求出所有的21位水仙花数,麻烦那个高手给个算法思路
...全文
5467 77 打赏 收藏 转发到动态 举报
写回复
用AI写文章
77 条回复
切换为时间正序
请发表友善的回复…
发表回复
simon_javaer 2013-12-20
  • 打赏
  • 举报
回复
原来高手都在这里
ltl520dj 2013-04-02
  • 打赏
  • 举报
回复
大神汇聚在此啊
Mr.Ding 2013-03-30
  • 打赏
  • 举报
回复
我溃败了,真的。。。
jafsldkfj 2012-11-13
  • 打赏
  • 举报
回复
引用 7 楼 g_idea 的回复:
最近这题总出现啊。 其实核心思想就是尽量减少组合的判断范围,来提高速度。 简单说一下思路: 1.数字9最多出现9个,其他数字分析与否都可以。 2. 如果9取9个,那么这种情况下,最大的数max为9*(9^21)+12*(8^21); 最小数min为9*(9^21)。如果max与min位数都为21位,那么可以分析两个数的组成部分, 其前面相同的部分是min到……
为什么是要出现9个9呢?
marchonchina 2012-11-10
  • 打赏
  • 举报
回复
佩服! 好多牛人啊
summer_hcz 2012-10-26
  • 打赏
  • 举报
回复
都是牛逼人物啊,学习了
ssfjhh 2012-07-18
  • 打赏
  • 举报
回复
def narcissistic(n):
length = len(str(n))
sumn = sum([int(i)**length for i in list(str(n))])
if n == sumn:
return True
else:
return False

if __name__ == '__main__':
for i in range(1000000000):
if narcissistic(i):
print(i)
boxer_tony 2012-05-04
  • 打赏
  • 举报
回复
综合了litaoye的剪枝,再加上对每个数字可取数字的范围的限定,速度进一步提高。在我的笔记本上,算39位的需要400毫秒左右。
从1位循环到60位,需要月9秒。不过39位以上就无解了。解最多的是11位,居然有8个解:
32164049650
32164049651
40028394225
42678290603
44708635679
49388550606
82693916578
94204591914
qiumin333 2012-04-22
  • 打赏
  • 举报
回复
牛人一大堆,菜鸟很傻眼!
lisency 2012-03-11
  • 打赏
  • 举报
回复

class WaterNum:
"""Search Water Num
.....................
"""
def __init__(self,N = 21):
self.N = N
self.sum = 0 # sum
self.k_sum = 0
self.pow21 = [pow(i * -1,self.N) for i in range(-9,1)]
self.length = [len(str(i)) for i in self.pow21]
self.count = [-1 for i in range(10)] # initialize zero
self.max_num = pow(10,N)
self.min_num = pow(10,N - 2)

print('pow21:',self.pow21)
print('length:',self.length)

def increase_sum(self,freq = 0):
""" add the new vlaue
"""
if freq != 0:
self.sum += self.pow21[self.k] * freq
self.k_sum += freq
elif self.count[self.k] != 0:
self.sum += self.pow21[self.k]
self.k_sum += 1


def decrease_sum(self):
""" minus the mistake value
"""
k = self.k
self.sum -= self.pow21[k] * self.count[k]
self.k_sum -= self.count[k]

def set_filter(self):
""" calculate the frequency of every digits
"""
#print(self.k)
#for index in range(self.k + 1,10):
#self.count[index] = 0
self.filter = [0 for i in range(10)]
sum_str = str(self.sum)
#print(sum_str)
s_temp = sum_str[:-self.length[self.k]]

for ch in s_temp:
self.filter[9 - int(ch)] += 1
#print(s_temp)
#print(self.filter)

def check(self):
""" check the frequency of the digits in the front is ok
"""
for index in range(self.k):
if self.count[index] < self.filter[index]:
#print('return False index:',index)
return False

if self.sum > self.max_num:
return False
#print('return True')
return True

def right_print(self):
""" if this is a right answer,print it
"""
s_str = str(self.sum)
count_temp = [0 for i in range(10)]
for ch in s_str:
count_temp[9 - int(ch)] += 1
for i in range(10):
if self.count[i] != count_temp[i]:
return False
print('found',s_str)
return True

def search(self):
""" begin search
.......................
"""
self.k = 0
self.count[self.k] += 1
while self.k >= 0:
self.count[self.k] += 1
self.increase_sum()
self.set_filter()
#print('count:',self.count,'sum:',self.sum,'k_sum',self.k_sum,'filter:',self.filter)

if self.check() == False:
#print('at 1')
self.decrease_sum()
self.k -= 1
elif self.k >= 9 or self.k_sum >= self.N:
#print('at 2')
self.right_print()
self.decrease_sum()
self.k -= 1
# this number is in the range,we judge it
else:
#print('at 3')
self.k += 1
f_num = self.filter[self.k] - 1
self.count[self.k] = f_num
if f_num > -1:
self.increase_sum(f_num)
# self.count[k] = -1


import time

if __name__ == '__main__':
water_num = WaterNum(39)
water_num.search()


python代码,差点就秒杀了
永不褪色的梦 2012-01-11
  • 打赏
  • 举报
回复
#include <iostream.h>
#include <time.h>
#include <math.h>
#include <stdio.h>
struct search
{
int a[10];
};
search SEARCH(search &a1,int *b,int n)//查找每个数的个数的函数。
{
for(int i=0;i<n;i++)
{
if(b[9-n+i]==9){a1.a[9]++;continue;}
if(b[9-n+i]==8){a1.a[8]++;continue;}
if(b[9-n+i]==7){a1.a[7]++;continue;}
if(b[9-n+i]==6){a1.a[6]++;continue;}
if(b[9-n+i]==5){a1.a[5]++;continue;}
if(b[9-n+i]==4){a1.a[4]++;continue;}
if(b[9-n+i]==3){a1.a[3]++;continue;}
if(b[9-n+i]==2){a1.a[2]++;continue;}
if(b[9-n+i]==1){a1.a[1]++;continue;}
if(b[9-n+i]==0){a1.a[0]++;continue;}
}
return a1;
}
int compare(search &a1,int *d)//比较个数是否相等。
{
for(int i=0;i<10;i++)
{
if(d[i]!=a1.a[i]) return 0;
}
return 1;
}
int POW(int a,int b)
{
int t=a;
if(b==0)return 1;
for(int i=1;i<b;i++)
a=a*t;
return a;
}
void main()
{
clock_t begin,end;
int d[10],p,b[9]={0},n,i;
search a1={0},a2;
cout<<"*******************************************************************************"<<endl;
cout<<"*********************1.查找3~9位数的花朵数*************************************"<<endl;
cout<<"*********************2.请输入n(3<=n&&n<=9)计算相应的花朵数*********************"<<endl;
cout<<"*********************3.输入其他报错!*******************************************"<<endl;
cout<<"*********************0.输入0退出***********************************************"<<endl;
cout<<"*******************************************************************************"<<endl;
cout<<"请输入:";
cin>>n;
if(n==0) return ;
if(n<3||n>9){cout<<"ERROR!"<<endl;return ;}
begin=clock();
for(d[9]=n;d[9]>=0;d[9]--)
for(d[8]=n-d[9];d[8]>=0;d[8]--)
for(d[7]=n-d[8]-d[9];d[7]>=0;d[7]--)
for(d[6]=n-d[7]-d[8]-d[9];d[6]>=0;d[6]--)
for(d[5]=n-d[6]-d[7]-d[8]-d[9];d[5]>=0;d[5]--)
for(d[4]=n-d[5]-d[6]-d[7]-d[8]-d[9];d[4]>=0;d[4]--)
for(d[3]=n-d[4]-d[5]-d[6]-d[7]-d[8]-d[9];d[3]>=0;d[3]--)
for(d[2]=n-d[3]-d[4]-d[5]-d[6]-d[7]-d[8]-d[9];d[2]>=0;d[2]--)
for(d[1]=n-d[2]-d[3]-d[4]-d[5]-d[6]-d[7]-d[8]-d[9];d[1]>=0;d[1]--)
for(d[0]=n-d[1]-d[2]-d[3]-d[4]-d[5]-d[6]-d[7]-d[8]-d[9];d[0]>=0;d[0]--)
//开始先存放每个位上的数到数组b中,在调用函数判断。
{
p=d[9]*POW(9,n)+d[8]*POW(8,n)+d[7]*POW(7,n)+d[6]*POW(6,n)+d[5]*POW(5,n)+d[4]*POW(4,n)+d[3]*POW(3,n)+d[2]*POW(2,n)+d[1]*1;
if(p>POW(10,n)) goto up;
if(p<=POW(10,n-1)) goto low;
for(i=0;i<n;i++)
{
b[8-i]=p%10;
p=p/10;
}
a2=SEARCH(a1,b,n);
if(compare(a2,d))
cout<<n<<"的花朵数为:"<<p<<endl;
up: ;
}
low: end=clock();
double c=(double)(end-begin)/CLOCKS_PER_SEC;
printf("计算时间为:%f\n",c);
}
本人学艺不精,请在线高手看看错在哪里。输出不了
匚匚 2011-08-31
  • 打赏
  • 举报
回复
发现C/C++的实现代码很少,传一个 ,只要几秒吧
http://blog.csdn.net/zhw952/article/details/6719985

//不依赖大数 速度较快

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cstring>
/**************************水仙花数**************************/
#define N 10

using namespace std;

void Narcissus(const int& n); //输出n位数中的水仙花数

int main(void)
{
clock_t start , end;
int n=1;
start=clock();

while(1)
{
std::cout<<"水仙花数位数:";
cin>>n;
start=clock();
Narcissus(n);
end=clock();
std::cout<<"Times:"<<(double)(end-start)/CLK_TCK<<std::endl;
}
//end=clock();
//std::cout<<"Times:"<<(double)(end-start)/CLK_TCK<<std::endl;
return 0;
}

static void StatNumber(int *num,int (&s)[N],const int& n)
{//统计num[]中 各数字出现的次数 结果放到S[]中
memset(s,0x00,sizeof(int)*N);
register int len=n;
const int* ptr=num;
while(len--)
{
++s[*ptr++];
}
}
static void Power_N(int *sum,const int& pow)
{ //对0~9的M次预处理将结果放入sum中,各数位拆解
register int i;
for(i = 1 ; i < N; i++) //初始化sum
{
sum[i*pow]=i;
}
for( i = 0 ;i < N; i++) //对0~9的M次预处理
{
int tmp;
for( int j = 0 ; (j < pow -1);j ++)
{
tmp=i*pow;
for( int n = 0 ; n < pow; n ++)
sum[tmp+n]*=i;
for(int m = 0 ; m < pow ; m ++)
{
if(sum[tmp+m]>=10)
{
if(sum[tmp+m+1] == -1)
sum[tmp+m+1] = 0;
sum[tmp+m+1] += sum[tmp+m]/10;
sum[tmp+m] = sum[tmp+m]%10;
}
}
}
}
}
static void Print(int *sum,const int& n)//输出水仙花数
{
register int i = n-1;
for(; i >= 0 ; i --)
{
std::cout<<sum[i];
}
std::cout<<std::endl;
}

static void add(int *addend,int *summend,const int& k,const int& pow )
{ //加入k的pow次方
register int i;
const int j=k*pow;
for( i = 0 ; i < pow; i ++)
addend[i] += summend[j+i];

for( i = 0 ; i < pow ; i ++)
{
if(addend[i]>=10)
{
if(addend[i+1] == -1)
addend[i+1] = 0;
addend[i+1] += addend[i]/10;
addend[i] = addend[i]%10;
}
}
}

static void sub(int *a,int *b,const int& k,const int& pow )//从a中减去k的pow次方
{
const int j=k*pow;
for(register int i = 0 ; i < pow; i++)
{
if(a[i] < b[j+i])
{
a[i+1] -= 1;
a[i]=a[i]+10-b[j+i];
}
else
{
a[i] -= b[j+i];
}
}
}
static bool cmp(int (&a)[N],int (&b)[N])//比较
{
for(register int i = 0 ; i < N; i++)
if(a[i]!=b[i])
return false;
return true;
}
void Narcissus(const int& n)
{
if(n <= 0) return;

int *sum=new int[n*N]; //0~9的n次方
memset(sum,0,sizeof(int)*n*N);

int stat1[N]={0}; //N次方和中各位数字出现的次数
int stat2[N]={0}; //栈中数出现的次数
int *gross=new int[n+1]; //栈中各数的n次方和 数字已拆分
memset(gross,0x00,sizeof(int)*(n+1));

int *stack=new int[n+1]; //栈
memset(stack,0x00,sizeof(int)*(n+1));
int* top=stack; //栈顶指针
const int *maxTop=stack+n; //

Power_N(sum,n); //求出0~9的n次方
bool tab = false;
register int k =9; //动态组合的数字 从大到小组合

while(1)
{
if(top < maxTop && gross[n]==0)
{ //栈中数字及N次方和均未达到N位
add(gross,sum,k,n);
stat2[k]++; //记录栈中各数字出现次数
*top++ = k; //数字入栈 栈顶不会大于后面的数字777-776.即780不会有
} //因无++K,只有--K.已出现过的组合后面不会再现 如731已现,无371/137/713/173

if(gross[n]>0) //组合数字的N次方和大于N位
{
sub(gross,sum,k,n);
stat2[k]--;
k=*--top - 1; //退栈,组合数字为退出数减一,后面不会有比前面更大的组合数字
}
if(top == maxTop) //栈满 即已有N位数字
{
if(gross[n-1]==0) //N次方和小于N位 若n为1,不能输出0,此处退出
break; //由于后面无比它更大的组合(见165-172行注释),退出
StatNumber(gross,stat1,n);//求N次方和中各位数出现次数 存于sta1中
if(cmp(stat1,stat2)) //若出现的数字及其次数完全相同,则为水仙花数
{
Print(gross,n); //若栈中为7 3 1则输出371
}
if(*(top-1) != 0) //若栈顶数字不为0
{
sub(gross,sum,k,n); //先从N次方和中减去此数字的N次方
--stat2[k]; //此数次数随即减少 此时栈顶指针未动
}
else
{
while(*(top-1) == 0) //栈顶为0 循环后指向栈中紧跟的非0数字
{
--top;
--stat2[0]; //退0
}
//if(top-1<stack) break;
tab=true;
}
k=*--top; //退栈 k接收退出的数字
if(tab)
{
sub(gross,sum,k,n); //
--stat2[k];
tab = false;
}
--k; //后面的组合数字比原数更小 保证不出现 788
}
//if(*stack ==1) break;
}
delete []sum;
delete []gross;
delete []stack;
}


xiaoxiami002 2011-06-27
  • 打赏
  • 举报
回复

import java.math.BigInteger;
import java.util.Arrays;

public class da2 {
static BigInteger[] table = new BigInteger[10];
static BigInteger sum = BigInteger.ZERO;
static int times = 0;
static BigInteger MAX = BigInteger.TEN.pow(21).subtract(BigInteger.ONE);
static BigInteger MIN = BigInteger.TEN.pow(21 - 1);
public static void main(String[] args) {
long time = System.nanoTime();
int n = 21;
int[] nums = new int[n];
//for(int i = 0;i < nums.length;i++)
//{
// nums[i] = 1; ------------把这删掉
//}
for (int i = 0; i < 10; i++)
table[i] = BigInteger.valueOf(i).pow(n);
f(0,n,nums,0);
time = System.nanoTime() - time;
System.out.println(time / 1000000000.0 + "s");
System.out.println("循环次数:"+times);
}

public static void f(int i,int n,int[] nums,int m)
{
if(i > n - 1)
{
times++;
if(panduan(nums))
System.out.println(sum);
}
else
{
for(int v = m;v < 10;v++)
{
nums[i] = v;
sum = sum.add(table[v]);
f(i+1,n,nums,v);
sum = sum.subtract(table[v]);
}
}
}
public static boolean panduan(int[] nums)
{
if(sum.compareTo(MAX)>0||sum.compareTo(MIN)<0)
return false;
String s = String.valueOf(sum);
int length = s.length();
int[] a = new int[length];
for (int i = 0; i < length; i++)
a[i] = s.charAt(i) - '0';
int[] b = nums.clone();
Arrays.sort(a);
Arrays.sort(b);
return Arrays.equals(a, b);
}
}
xiaoxiami002 2011-06-27
  • 打赏
  • 举报
回复
一个很简单的算法:


import java.math.BigInteger;
import java.util.Arrays;

public class da2 {
static BigInteger[] table = new BigInteger[10];
static BigInteger sum = BigInteger.ZERO;
static int times = 0;
static BigInteger MAX = BigInteger.TEN.pow(21).subtract(BigInteger.ONE);
static BigInteger MIN = BigInteger.TEN.pow(21 - 1);
public static void main(String[] args) {
long time = System.nanoTime();
int n = 21;
int[] nums = new int[n];
for(int i = 0;i < nums.length;i++)
{
nums[i] = 1;
}
for (int i = 0; i < 10; i++)
table[i] = BigInteger.valueOf(i).pow(n);
f(0,n,nums,0);
time = System.nanoTime() - time;
System.out.println(time / 1000000000.0 + "s");
System.out.println("循环次数:"+times);
}

public static void f(int i,int n,int[] nums,int m)
{
if(i > n - 1)
{
times++;
if(panduan(nums))
System.out.println(sum);
}
else
{
for(int v = m;v < 10;v++)
{
nums[i] = v;
sum = sum.add(table[v]);
f(i+1,n,nums,v);
sum = sum.subtract(table[v]);
}
}
}
public static boolean panduan(int[] nums)
{
if(sum.compareTo(MAX)>0||sum.compareTo(MIN)<0)
return false;
String s = String.valueOf(sum);
int length = s.length();
int[] a = new int[length];
for (int i = 0; i < length; i++)
a[i] = s.charAt(i) - '0';
int[] b = nums.clone();
Arrays.sort(a);
Arrays.sort(b);
return Arrays.equals(a, b);
}
}
tylanbin 2011-06-13
  • 打赏
  • 举报
回复
全是大神……
CherylNatsu 2011-05-21
  • 打赏
  • 举报
回复

#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include <sys/time.h>

#define N 21
#define NUMBER_LENGTH_MAX 30

struct number
{
char digits[NUMBER_LENGTH_MAX];
int length;
};

struct counter
{
int digits[10];
int offset;
};

void assign(struct number *a, int b)
{
a->length = 0;
memset(&a->digits[0], 0, NUMBER_LENGTH_MAX);
if (b == 0) a->length = 1;
while(b > 0)
{
a->digits[a->length++] = b % 10;
b /= 10;
}
}

void copy(struct number *src, struct number *dst)
{
dst->length = src->length;
memcpy(&dst->digits[0], &src->digits[0], NUMBER_LENGTH_MAX);
}

void print(struct number *a)
{
char *p = &(a->digits[0]);
char *endp = &(a->digits[0]) + a->length;
do
{
endp--;
printf("%c", "0123456789"[(int)*endp]);
}while(endp != p);
}

void add(struct number *a, struct number *b)
{
int len = (a->length > b->length) ? a->length : b->length;
int i;
int carry = 0;
int d;
for (i = 0; i < len; i++)
{
d = (a->digits[i] + b->digits[i] + carry);
a->digits[i] = d % 10;
carry = d / 10;
}
if (carry > 0)
{
a->digits[len] = carry;
len++;
}
a->length = len;
}

void mul(struct number *a, int b)
{
int carry = 0;
char *p = &(a->digits[0]);
char *endp = &(a->digits[0]) + a->length;
while(p != endp)
{
int d = carry + *p * b;
*p = d % 10;
carry = d / 10;
p++;
}
if (carry > 0)
{
*p = carry;
a->length++;
}
}

int judge(struct counter *ctr, struct number *b, struct number *table)
{
static struct number t;
static int i;
assign(b, 0);
for (i = 9; i >= ctr->offset; i--)
{
if (ctr->digits[i] > 0)
{
copy(&table[(i * (N + 1)) + ctr->digits[i]], &t);
add(b, &t);
}
}
static struct counter new_ctr;
memset(&new_ctr, 0, sizeof(new_ctr));
new_ctr.offset = 0;
char *p = b->digits;
char *endp = b->digits + b->length;
if (b->length != N) return 0;
while (p != endp)
{
new_ctr.digits[(int)*p]++;
p++;
}
for (i = 0; i < ctr->offset; i++)
{
if (new_ctr.digits[i] != 0) return 0;
}
for (i = ctr->offset + 1; i < 10; i++)
{
if (ctr->digits[i] != new_ctr.digits[i]) return 0;
}
return 1;
}

int iter(struct number *table)
{
struct counter ctr;
ctr.offset = 9;
int remain = 0;
ctr.digits[9] = N;
while (1){
if (remain == 0)
{
struct number sum;
if (judge(&ctr, &sum, table))
{
print(&sum);printf("\n");
}
if (ctr.digits[ctr.offset] > 0)
{
ctr.digits[ctr.offset]--;
remain++;
}
else
{
while (ctr.digits[ctr.offset] == 0) ctr.offset++;
}
}
else
{
if (ctr.offset > 0)
{
ctr.offset--;
ctr.digits[ctr.offset] = remain;
remain = 0;
}
else
{
if (ctr.offset == 0 && remain == N) return 0;
while (ctr.digits[ctr.offset] == 0) ctr.offset++;
ctr.digits[ctr.offset]--;
remain++;
}
}
}
return 0;
}

void init_table(struct number *table)
{
int i, j;
for (i = 0; i < 10; i++)
{
assign(&table[i * (N + 1)], 0);
assign(&table[i * (N + 1) + 1], i);
for (j = 0; j < N - 1; j++)
{
mul(&table[i * (N + 1) + 1], i);
}
for (j = 2; j <= N; j++)
{
copy(&table[i * (N + 1) + j - 1], &table[i * (N + 1) + j]);
add(&table[i * (N + 1) + j], &table[i * (N + 1) + 1]);
}
}
}

int main(int argc, const char *argv[])
{
struct number *table = (struct number *)malloc(sizeof(struct number) * ((N + 1) * 10));
struct timeval time1, time2;
gettimeofday(&time1, NULL);
init_table(table);
iter(table);
free(table);
gettimeofday(&time2, NULL);
printf("time:%lu:%lu\n", time2.tv_sec - time1.tv_sec, time2.tv_usec - time1.tv_usec);
return 0;
}


我的机器上gcc 4.4用O2,15秒才出结果。
哪位帮我指点一下我的程序有什么问题,谢谢。
CherylNatsu 2011-05-21
  • 打赏
  • 举报
回复
我拼了老命也还是15秒才行,不知道怎么回事。
chendongbox 2011-05-20
  • 打赏
  • 举报
回复
这个问题最好的方法是查表法。
k1060220963 2011-05-20
  • 打赏
  • 举报
回复
这个问题最好的方法是查表法。
l98766666 2011-05-16
  • 打赏
  • 举报
回复
我的具体思路是999999999999999999999999999 逐减1 并且后一位数字不比前一位大,把这个数所有数字的n次方相加得到的结果中0~9的个数与原数中0~9的个数相同,那么得到的结果就是一个水仙花数
例如999999999999999999999999990减1后是999999999999999999999999988
加载更多回复(51)

33,009

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧