跳题是因为有些题简单没有写的必要,或者难度大需要在后面写,循序渐进~
030题:
该题与Project Euler-034和Project Euler-036类似,有时间的童鞋可以看一下那两道题
题意:
有三个数可以写成它们各位数字的四次幂之和:
1634 = 1^4 + 6^4 + 3^4 + 4^4
8208 = 8^4 + 2^4 + 0^4 + 8^4
9474 = 9^4 + 4^4 + 7^4 + 4^4
由于1 = 1^4不是一个和,所以这里并没有把它包括进去。
这些数的和是1634 + 8208 + 9474 = 19316。
找出所有可以写成它们各位数字的五次幂之和的数,并求这些数的和。
思路:
遇到这个题,我们首先需要确定它的上界是什么,不然暴力枚举都不知道终止条件。
对于每一位来说,9^5最大,因此我们通过每位都是9的数来确定它的上界。我们设上限为n
当n为二位数时,最大累计和为六位数; 当n为三位数时,最大累计和为六位数; 当n为四位数时,最大累计和为六位数; 当n为五位数时,最大累计和为六位数; 当n为六位数时,最大累计和为六位数; 当n为七位数时,最大累计和为六位数。
从上边就可以看出,当一个数为7位数及更大,它的最大累计和都不足该数的位数,说明n的上限为6位数。
因此,我有以下两个思路:
思路一:求出6个9^5的和为354294,然后遍历2~354294之间的数,只要满足条件就累加求和,时间复杂度为1e6
思路二:分别求出0~9的五次方(快速幂),然后遍历位数(从2~6),多少位就相当于取多少个数(利用dfs剪枝),只需判断这些数的五次方和是否为与位数相同且等同与这几个数,相同就累加,时间复杂度大概1e5(就相当于有10种球,每种球无限个,同时取2个,3个,4个,5个,6个的方案数,经计算只有7997种)
代码:
老规矩,暴力代码不写:
#include <stdio.h>
#include <string.h>
int num[10];
int ans;
int book1[10], book2[10];
int sss = 0;
//快速幂函数
int quick (int a, int b) {
int res = 1;
while (b) {
if (b & 1) res *= a;
a *= a;
b >>= 1;
}
return res;
}
//预处理0~9的五次方
void init () {
memset (num, 0, sizeof(num));
for (int i = 0; i < 10; i++) {
num[i] = quick (i, 5);
}
}
//dfs剪枝求当为n位数的不同数字组合
void dfs(int now, int inx, int n, int val) {
if (inx == n) {
sss ++; //计算枚举的个数
memset (book2, 0, sizeof(book2));
int vall = val, flag = 0;
while (vall) {
book2[vall % 10] ++;
vall /= 10;
}
for (int i = 0; i < 10; i ++) {
if (book1[i] != book2[i]) {
flag = 1;
break;
}
}
if (!flag) {
ans +=val;
}
return;
}
//剪枝精髓
for (int i = now; i < 10; i++) {
book1[i] ++;
dfs (i, inx + 1, n, val + num[i]);
book1[i] --;
}
return;
}
int main () {
init();
ans = 0;
for (int i = 2; i <= 6; i ++) {
memset(book1, 0, sizeof(book1));
dfs(0, 0, i, 0);
}
printf("%d\n", ans);
//printf("%d\n", sss); //真正枚举的个数,只有7997
return 0;
}
最后输出答案为: 443839
如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢