21位花朵数

一个N位的十进制正整数,如果它的每个位上的数字的N次方的和等于这个数本身,则称其为花朵数。


例如:


当N=3时,153就满足条件,因为 1^3 + 5^3 + 3^3 = 153,这样的数字也被称为水仙花数(其中,“^”表示乘方,5^3表示5的3次方,也就是立方)。


当N=4时,1634满足条件,因为 1^4 + 6^4 + 3^4 + 4^4 = 1634。


当N=5时,92727满足条件。


实际上,对N的每个取值,可能有多个数字满足条件。


程序的任务是:求N=21时,所有满足条件的花朵数。注意:这个整数有21位,它的各个位数字的21次方之和正好等于这个数本身。


如果满足条件的数字不只有一个,请从小到大输出所有符合条件的数字,每个数字占一行。因为这个数字很大,请注意解法时间上的可行性。要求程序在3分钟内运行完毕。


 


【程序运行参考结果】


128468643043731391252


449177399146038697307


本题的思路:


1:关键是:去掉所含0-9数字个数相同的21位数,以免重复运算,增加时间,比如123456789012345678901与987654321098765432101与987654321012345678901中的所含数字的个数都是相同的,所以其每一位的21次方的和都相等,将所得的21次方和 从大到小进行排序,若对应的数与原数不相等,则都不成立,因此若不去掉重复的数,将会增加运算时间;


2:以为要将每一位数的21次方之和从大到小排序,所以运算从21个9这个最大数开始向下运算,又因为10个9的21次方之和超过了21位数,所以从9个9,12个8开始一次往下运算即可,这样又可以节约一部分时间。


#include "iostream"
#include "string.h"
#define N 21
using namespace std;
int a[10][N+1];  //记录每个数的21次方是多少 
int book[10];  //记录每个数多少个 
int flag[10];  //标记每个数21次方的最高位 

int sum[10][N+1];  //计算每个数的book[i]个和 
int result[N+1];  //总和 

bool X(int where,int num);
void handle();   //清理 
bool add();   
void test(); //检验 
int main(){
     handle(); 
	void first();  //初始化每个数的N次方 
	void dfs(int k,int sum);
	first();
	dfs(0,21);
	return 0;
}
void first(){
	int i,temp,j,k;
    //i 枚举0-9 
    for(i=0;i<10;i++)//对0-9每个数的21次方 分别存入数组a[i][N+1]中
    {
         a[i][0]=1;      //初始第一位要为1 
     for(k=0;k<N;k++)  //枚举21次方 
     {
         temp=0;   //上一个数的进位 
         for(j=0;j<N;j++)   //枚举第几位数 
         {
         	int now=temp+a[i][j]*i;   //上一位的进位+该位 
            a[i][j]=now%10;  //该位  
            temp=now/10;  //进位 
         }
     }
    }
    //输出测试 
   /* for(i=0;i<=9;i++)
    {
    	for(j=N-1;j>=0;j--)
    	cout<<a[i][j];
    	cout<<endl;
    }*/
}

//求每个数字可以为几个 k
void dfs(int k,int sum){       //sum还有几个  k第几个 
	if(sum==0){
		test();
		return;
	}
	if(k==9){
		book[k]=sum;
		dfs(k+1,0);
		return; 
	}
	int i;
	for(i=0;i<=sum;i++)
	  {
	  	book[k]=i;	  
	  	dfs(k+1,sum-i);
	  	book[k]=0;
	  }
}


void test(){
	if(book[9]>9||book[8]>11) 
		    return; 
	int i;
	for(i=0;i<=9;i++){   //相乘 
		if(X(i,book[i])==0){
			handle(); 
		return;
	}	
	}
	
	 //相加 
		if(add()==0) {
			handle(); 
		return;		
	}
  
    int f[10];
    for(i=0;i<=9;i++)  //初始化检验数组 
     f[i]=0;
    for(i=0;i<N;i++){         //检测每位结果 
       f[result[i]]++;
    }
    for(i=0;i<=9;i++){      
       if(f[i]!=book[i])
       {
       		handle(); 
		return;		
       }
    }
	for(i=N-1;i>=0;i--)
	cout<<result[i];
	cout<<endl;	 
}

bool add(){
	int i,j,temp;	
	for(i=1;i<=9;i++)  //0-9 sum
	 {	
	    temp=0;
	 	for(j=0;j<=N;j++){
	 		int now=temp+sum[i][j]+result[j]; 
			 result[j]=now%10;
			 temp=now/10;
	 	}
	 }	
	 if(result[N]>0||result[N-1]==0)
	 	return false;
	else
	 return true;
} 

bool X(int where,int num){  //每个数有几个 相乘 
	int i;
	int temp=0;
	for(i=0;i<=N;i++)  //21位 
	{
	   int now=temp+a[where][i]*num;
	   sum[where][i]=now%10;
	   temp=now/10;  	   
	}
	if(sum[where][N]>0)
	   return false;
	else 
	return true;
} 

void handle(){
	memset(result,0,sizeof(result));
	memset(sum,0,sizeof(sum));
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值