花朵數_藍橋杯題目

一個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次方之和正好等於這個數本身。

解題思路:花朵數爲21位數,肯定不是int/long所能表示的範圍,所以本題使用大整數來表示。
那麼有的同學可能想到了使用for循環遍歷100…000~999…999這麼多的21位數進行暴力破解,但是這個計算量是非常巨大的,計算機無法處理,那麼我們應該怎麼尋找其中符合條件的數呢?
有的同學可能想到了,21位數當中一定有許多重複的累加和。到這裏也就不難想了,決定21位數字冪累加的和並不取決於數字的順序,而是每個數字出現的次數。·
現在我們只需要對這個次數進行遍歷就行了,這樣我們的計算量就大大縮小了。
我們設置一個存放每個數字出現次數的數組,對它進行遍歷,枚舉21位數字的出所有可能。對每個可能都做計算,判斷它是否爲一個21位數,這個21位數中每個數字出現的個數是否與我們的數組一致。這樣我們就可以得到這個21位花朵數了。

首先我們看一下大整數的方法:

vauleOf(int) 將整型數據轉換爲大數據
multiply() 大數據乘法
add() 大數據加法
.ZERO/.ONE 大數據0、1的定義

最後的計算結果比較:由於記錄21位數據的方法採用的是一個存儲數字出現次數的數組,所以要進行數組的判斷。這裏的比較方法是將計算的結果化爲字符串s,對s中的字符進行解析化爲數組,與原數組比較。

import java.math.BigInteger;

public class X11 {
static BigInteger[] x = new BigInteger[10];

public static BigInteger pow_21(int n){
    BigInteger b = BigInteger.ONE;
    for(int i=0;i<21;i++){
    b = b.multiply(BigInteger.valueOf(n));//21次乘以n,得n^21
    }
    return b;
}

public static void test(int[] a){
    BigInteger sum = BigInteger.ZERO;//總和
    for(int i=1;i<10;i++){//加9次(0的21次方等於0,不需要加)
        sum = sum.add(x[i].multiply(BigInteger.valueOf(a[i])));//valueOf(int) 方法對int進行轉換爲BigInteger大整數
    }
    //接下來比較
    String s = sum.toString();//大整數,使用字符串進行比較
    if(s.length() != 21) return;

    int[] a1 = new int[10];//注意是與a[]進行比較,所以需要將大整數的結果字符串進行解析

    for(int i=0;i<21;i++){
        a1[s.charAt(i) - '0']++;//按位處理結果,轉換爲a1[] 的數據
    }
    //比較
    for(int i=0;i<10;i++){
        if(a1[i] != a[i]) return;
    }

    System.out.println(s);
}

//x存放數字的21次方數據 , a存放數字出現次數 , cur當前處理的數字 , use已經使用的位數
public static void f(int[] a,int cur,int use){
    if(use == 21){
        test(a);
        return;
    }

    if(cur==9){//9個數字枚舉完畢,進行計算判斷
        a[9] = 21-use;
        test(a);//測試是否成功找到數字
        return;
    }

    //枚舉
    for(int i=0; i<21-use; i++){

        a[cur] = i;//當前數字出現的次數:i
        f(a,cur+1,use+i);
        a[cur] = 0;//不要忘記回溯
    }
}

public static void main(String[] args) {
    //0~9的21次方給數組x[]
    for(int i=0; i<10; i++){
        x[i] = pow_21(i);//pow_21 方法計算21次方
    }
    int[] a = new int[10];//記錄每個數字出現的次數

    f(a,0,0);//遞歸主方法
    }
}
//結果
//128468643043731391252
//449177399146038697307

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章