zoukankan      html  css  js  c++  java
  • 21位花朵数(详解)

    ~~ 转载请注明出处^^

    今天看到了,蓝桥杯上面的一道题,求21位花朵数,题目是:

    l  (编程题)花朵数

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

    例如:

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

    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<stdio.h>
    #include<time.h>
    #include<string.h>
    //#include<conio.h>
    //#include<math.h>
    //有的注释 是用来测试数据
    #define N 21
    int a[10][N+1];
    void fun()
    {
        int i,temp,j,k;
        for(i=0;i<10;i++)//对0-9每个数的21次方 分别存入数组a[i][N+1]中
        {
             a[i][0]=1;
         for(k=0;k<N;k++)
         {
             temp=0;
             for(j=0;j<N;j++)
             {
                temp=temp/10+a[i][j]*i;
                a[i][j]=temp%10;
             }
         }
        }
        for(i=0;i<10;i++)
        {
            for(j=N-1;j>=0;j--)
            if(a[i][j]!=0)break;
            
            a[i][N]=j+1; //记录从第几个开始之后全部为0
        }
        //可以在此处输出结果以供检查错误
        /*for(i=0;i<10;i++)
        {
            printf("i=%d\n",i);
            for(j=0;j<N+1;j++)
            printf("%3d",a[i][j]);
            printf("\n");
        }*/
    }
    void fun1()
    {
        int b[N];
        int c[N]={0},d[N]={0},e[10]={0};//c[N]存b[N]中每个数字的21次方之和
        int x,i,j,k,temp,flag;  //d[N]存c[N]从大到小排好序的值
        int f[100][21];  //用来存放满足条件的数 然后从小到大输出
        for(i=0;i<9;i++)  //b[N]存从99……99到100……00之间的数 初始化为9个9后面全是8,因为10个9的21次方之和将超过21位数
         b[i]=9;
        for(i=9;i<N;i++)
         b[i]=8;
         k=0;//先将满足条件的数组个数清为0
        while(b[0]!=0)    //e[N]存中间排序的中间量 选择的排序方法比较特别(已知最大值的排序)
        {
            flag=1;
            
            //求21个数的21次方之和
            for(i=0;i<N;i++)
            {
                temp=0;
                for(j=0;j<N;j++)
                {
                    temp=temp/10+a[b[i]][j]+c[j];
                    c[j]=temp%10;
                    if(j==N-1&&temp>9) //
                    {
                        flag=0;
                        //printf("超过21位数\n");
                        break;
                    }
                    if(a[b[i]][j]==0&&j>=a[b[i]][N])break;//
                }
                if(flag==0)break;//  这些都是为了节省时间 进行程序优化
                
            }
            //getch();
            if(c[N-1]==0)flag=0;        
            if(flag)
            {
                //将c[N]排序 注意排序方法 复杂度较低
            x=0;
            for(i=0;i<N;i++)
             e[c[i]]++; //分别有几个0到9 存到e[N]中  曾将c[i]错写成b[i]~~
            for(i=10-1;i>=0;i--)
            {
             for(j=0;j<e[i];j++)
                  d[x++]=i;
            }
            
            //比较二者是否相等
            for(i=0;i<N;i++)
            {
                if(b[i]!=d[i])
                {
                    flag=0;
                    break;
                }
            }
            }//if
            //如果标记falg=1则输出结果
            if(flag)
            {
                /*printf("输出结果为:");
                for(i=N-1;i>=0;i--)
                printf("%d",c[i]); 将c[i]曾错写成b[i]
                printf("\n");若这样输出则为从大到小输出*/
                j=0;
                for(i=N-1;i>=0;i--)
                 f[k][j++]=c[i];
                 k++;
            }
            //找下一个a[N]
            for(i=N-1;i>=0;i--)
             if(b[i]!=0)  //此处曾经出错 将b[i]写成a[i]
             break;
             temp=b[i];
            // printf("temp=%d ",temp);
            while(i<N)
            {
                b[i++]=temp-1; //保证去掉重复的数  并按从大到小顺序 进行处理
            }
            //printf("b[2]=%d b[3]=%d\n",b[2],b[3]);    
            
            memset(c,0,sizeof(c));//全部置0 因为后面还要用
            memset(d,0,sizeof(d));
            memset(e,0,sizeof(e));
        }
        //从小到大输出
        for(i=k-1;i>=0;i--)
         {
             for(j=0;j<N;j++)
             printf("%d",f[i][j]);
             printf("\n");
         }
    }
    int main()
    {
        fun();
        fun1();
        
        printf("\n程序运行了%.2lf秒\n",(double)clock()/CLOCKS_PER_SEC);//只是为了测试一下程序运行的时间
        return 0;
    }

     程序运行结果:

    此题目应该还可以再优化,不过已经很满足了题目要求。若谁有更为简单的方法,别忘了与大家共享哦!

    ~~ 转载请注明出处^^

  • 相关阅读:
    NPOI开发手记
    jQuery.form开发手记
    jQuery.Flot开发手记
    node.js初探
    Linux私房菜阅读笔记
    c#实现常用排序算法
    Excel自定义函数开发手记
    浅谈知识管理
    Git学习手记
    c# 屏蔽快捷键
  • 原文地址:https://www.cnblogs.com/hsqdboke/p/2447079.html
Copyright © 2011-2022 走看看