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;
}

 程序運行結果:

此題目應該還可以再優化,不過已經很滿足了題目要求。若誰有更為簡單的方法,別忘了與大家共享哦!

~~ 轉載請注明出處^^


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM