基于C++实现水仙花数
1、水仙花数的连营
1.1、水仙花数
在学习程序设计课程时,大多数读者一定采用循环结构编写过求解水仙花数的程序。
【实例 1-1】水仙花数
一个三位整数(100~999),若各位数的立方和等于该数自身,则称其为“水仙花数”(如:153=13+53+33),找出所有的这种数。
编程思路
对三位数 n(n 为 100~999 之间的整数)进行穷举。对每个枚举的 n,分解出其百位 a(a=n/100)、十位 b(b=n%100/10)和个位 c( c=n%10),若满足 aaa+bbb+ccc== n,则 n 是水仙花数。
源程序及运行结果
# include <iostream>
using namespace std;
int main(){int n, a, b, c; //n、a、b和c分别为三位数自身及其百位、十位和个位for(n=100 ;n<=999;n++) {a=n/100;b=n%100/10;c=n%10; if(a*a*a+b*b*b+c*c*c== n)cout<<n<<" ";}cout<<endl;return 0; }
编译并执行以上程序,得到如下所示的结果。
153 370 371 407
Press any key to continue
1.2、 水仙花数的初步连营
在“三国杀”游戏中,武将陆逊有一个技能是“连营”,其技能描述是:每当你失去最后一张手牌时,可立即摸一张牌。借用这个概念,在程序设计实践中,我们设计了一个程序后,可以在这个程序的基础上,再进行扩展,提出相类似的另一个问题,再进行设计。即解决一个问题后,再解决一个问题,类比解释就是失去一张手牌后,再摸一张牌。在前面水仙花数问题的基础上,我们通过连营,可以提出下面几个问题。
【实例 1-2】4 位花朵数
一个四位整数(1000~9999),若其各位数的 4 次方之和等于该数自身,则称其为 4 位花朵数(如:1634=14+64+34+44),找出所有的这种数。
编程思路
编程的思路完全类同于水仙花数。即对四位数 n(n 为 1000~9999 之间的整数)进行穷举。对每个枚举的 n,分解出其千位 a(a=n/1000)、百位 b(b=n%1000/100)、十位 c(b=n%100/10)和个位 d(d=n%10),若满足 aaaa+bbbb+cccc+dddd== n,则 n 是 4 位花朵数。
源程序及运行结果
#include <iostream>
using namespace std;int main()
{int n, a, b, c,d; //n、a、b、c和d分别为四位数自身及其千位、百位、十位和个位for(n=1000 ;n<=9999;n++) {a=n/1000;b=n%1000/100;c=n%100/10;d=n%10; if(a*a*a*a+b*b*b*b+c*c*c*c+d*d*d*d==n)cout<<n<<" ";}cout<<endl;return 0; }
编译并执行以上程序,得到如下所示的结果。
1634 8208 9474
Press any key to continue
【实例 1-3】5 位花朵数
一个 5 位整数(10000~99999),若其各位数的 5 次方之和等于该数自身,则称其为 5 位花朵数(如:54748=55+45+75+45+85),找出所有的这种数。
编程思路
仍然可以采用完全类同于水仙花数的求解方法来求出所有的 5 位花朵数。即对 5 位数 n(n 为 10000~99999 之间的整数)进行穷举。对每个枚举的 n,分解出其万位 a(a=n/10000)、千位 b(b=n%10000/1000)、百位 c(c=n%1000/100)、十位 d(d=n%100/10)和个位 e(e=n%10),若满足 aaaaa+bbbbb+ccccc+ddddd+eeeee== n,则 n 是 5 位花朵数。
源程序及运行结果
#include <iostream>
using namespace std;int main(){int n, a, b, c,d,e; //n、a、b、c和d分别为5位数自身及其万、千、百、十和个位for(n=10000 ;n<=99999;n++) {a=n/10000;b=n%10000/1000;c=n%1000/100;d=n%100/10;e=n%10;if(a*a*a*a*a+b*b*b*b*b+c*c*c*c*c+d*d*d*d*d+e*e*e*e*e==n)cout<<n<<" ";}cout<<endl;return 0; }
编译并执行以上程序,得到如下所示的结果。
54748 92727 93084Press any key to continue
仿照实例 1-2 和 1-3 的方法,我们可以求解出所有的 6 位花朵数、7 位花朵数等等。但是按照上面的方法,都需要修改程序,在程序中相应地增加变量、添加语句。能不能输入一个自然数 N(为简单起见,N<=9,因为 C++ 中 32 位整数的最大值为 2147483647,更多的位数会超过 int 型数据的表数范围),求解出所有的 N 位花朵数呢?
1.3、 水仙花数的进一步连营
【实例 1-4】N 位花朵数
一个 N 位的十进制正整数,如果它的每个位上的数字的 N 次方的和等于这个数本身,则称其为 N 位花朵数。
例如:当 N=3 时,153 就满足条件。当 N=4 时,1634 满足条件。当 N=5 时,54748 满足条件。
实际上,对 N 的每个取值,可能有多个数字满足条件。编写程序,对输入的 N(N<=9),求出所有的 N 位花朵数。
编程思路
为求解 N 位的花朵数,需要对 N 位数 x(x 为 10N-1~10N-1 之间的整数)进行穷举。对每个枚举的 x,求出其每个位上的数字的 N 次方的和 digitsum,若满足 digitsum==x,则 x 是 N 位花朵数。
为求解 N 位花朵数,可以抽象两个函数。一个是 int power(int x,int n),用于求 x 的 n 次方;另一个是 int digitsum(int x,int n),用于求 x 的各位数的 n 次方之和。
源程序及运行结果
# include <iostream># include <ctime>using namespace std;int power(int x,int n){int i,p=1;for (i=1;i<=n;i++)p*=x;return p;}int digitsum(int x,int n){int s=0;while(x!=0){s+=power(x%10,n);x=x/10;}return s;}int main(){int n, x,a, b; //a、b分别为相应穷举区间的上下界限cin>>n;a=power(10,n-1);b=power(10,n)-1;int start=clock();for(x=a; x<=b; x++) {if(digitsum(x,n)==x)cout<<x<<" ";}cout<<endl<<"Running Time :"<<clock()-start<<" ms."<<endl;return 0; }
编译并执行以上程序,若输入 5,可得到如下所示的结果。
554748 92727 93084Running Time :16 ms.Press any key to continue
若输入 7,可得到如下所示的结果。
71741725 4210818 9800817 9926315Running Time :3234 ms.Press any key to continue
若输入 8,可得到如下所示的结果。
824678050 24678051 88593477Running Time :39282 ms.Press any key to continue
若输入 9,可得到如下所示的结果。
9146511208 472335975 534494836 912985153Running Time :457875 ms.Press any key to continue
上面的程序可以根据输入的 N,求出所有的 N 位花朵数。但从执行结果可以看出,求 7 位花朵数用时 3234ms,比求 5 位花朵数的 16ms 多得多。求 9 位花朵数更是用时 457875ms。能否想一些办法更快速地求解呢?
实际上,在我们解决问题时,当数据量比较小时,采用什么样的办法都无所谓,因为一般都能快速得到结果;但当数据量比较大时,就需要对解决问题的办法进行优化了,否则,时间上的开销是难以接受的。
2、花朵数的集智
2.1、花朵数的初步集智
在“三国杀”游戏中,武将黄月英有一个技能是“集智”,其技能描述是:每当你使用一张非延时类锦囊,(在它结算之前)你可以立即摸一张牌。也就是说,当黄月英在游戏中打出诸如无中生有、顺手牵羊、过河拆桥、借刀杀人、五谷丰登、南蛮入侵、万箭齐发、决斗、桃园结义、无懈可击、铁锁链环等牌时,可以另外摸一张牌。
借用这个概念,在程序设计实践中,我们设计了一个程序后,可以在这个程序的基础上,再进行优化和扩展,看能否采用另外的、更好的方法来解决这个问题。即采用一种方法解决一个问题后,再采用另外的方法来解决这个问题,也就是打出一张非延时类锦囊牌后,再摸一张牌(看能否找到一种更好的解法)。
下面对实例 1-4 中的程序进行初步的优化。
从给出的程序中可以看出,对于每个枚举的数 x 的每一位(x%10),程序中都会调用 power 函数求它的 n 次方。例如,若输入的是 5,则穷举 90000 个 5 位数(10000~99999),每个数有 5 位,则 power 函数会被调用 450000 次。
实际上,每次调用 power 无非是求 0~9 这 10 个数字中某个数字的 n 次方。因此,若事先调用 power 函数将 0~9 的 n 次方求出来并存放在一个数组中,则在求 x 的各位数字的 n 次方之和时,只需要取用数组中相应的值即可,而无需反复调用 power 函数。这样一定可以缩短求解的时间。
采用这个思路优化后的源程序如下:
#include <iostream>
#include <ctime>using namespace std;int table[10];int power(int x,int n){int i,p=1;for (i=1;i<=n;i++)p*=x;return p;}int digitsum(int x,int n){int s=0;while(x!=0){s+=table[x%10]; // 直接引用表中预先求得的值x=x/10;}return s;}int main(){int n, x,a, b; //a、b分别为相应穷举区间的上下界限cin>>n;a=power(10,n-1);b=power(10,n)-1;int start=clock();for (x=0; x<=9; x++) // 初始化数据表table[x]=power(x,n);for(x=a; x<=b; x++) {if(digitsum(x,n)==x)cout<<x<<" ";}cout<<endl<<"Running Time :"<<clock()-start<<" ms."<<endl;return 0; }
编译并执行以上程序,若输入 7,得到如下所示的结果。
71741725 4210818 9800817 9926315Running Time :984 ms.Press any key to continue
若输入 8,得到如下所示的结果。
824678050 24678051 88593477Running Time :11125 ms.Press any key to continue
从执行结果可以看出,采用打表的方法后,求解耗时明显减少了。
2.2、花朵数的进一步集智
上面的程序虽然效率得到了提升,但仍然不理想。例如,执行上面的程序,若输入 9,可得到如下所示的结果。
9146511208 472335975 534494836 912985153Running Time :125563 ms.Press any key to continue
从运行结果可以看出,求 9 位的花朵数,耗时近 2 分钟。下面我们来寻找更好的方法来解决求 N 位花朵数这个问题。
实例 1-3 中求 5 位花朵数是对所有的 90000 个 5 位数(10000~99999)进行穷举,看每个数的各位数字的 5 次方之和是否等于这个数字。实际上,可以穷举 0~9 这 10 个数字出现的次数(每个数字都可能出现 0~5 次),当所有数字出现次数之和等于 5 时,说明这时数字的组合有可能为 5 位花朵数,进而求出每个数字的 5 次方分别乘以其出现的次数的和值 sum,再判断 sum 内各个数字出现的次数是否与穷举各个数字时每个数字出现的次数分别相同,若相同,则 sum 就是一个 5 位花朵数。
例如,当穷举到数字 2 出现了 2 次、7 出现 2 次、9 出现 1 次时,由于 2+2+1=5,此时计算 sum=225+275+1*95=64+33614+59049=92727,检查得到的和 sum 的各个位,若恰好出现 2 个 2、2 个 7 和 1 个 9,说明这种数字组合使得其和为 5 位花朵数。
按这样的思路穷举,只需处理 2002 种情况。这是因为新思路是对数字出现的次数进行穷举。共有 7 种情形:
- 5 位数中每个数字只出现 1 次(即 1+1+1+1+1),有种情况。
- 5 位数中 1 个数字出现 2 次、另 3 个数字各出现 1 次(即 1+1+1+2),有种情况。
- 1+2+2(即 1 个数字出现 1 次,一个数字出现 2 次,还有一个数字出现 2 次)有种情况。
- 1+1+3(即 1 个数字出现 1 次,另一个数字也出现 1 次,还有一个数字出现 3 次)有种情况。
- 1+4(即 1 个数字出现 1 次,另一个数字出现 4 次)有种情况。
- 2+3(即 1 个数字出现 2 次,另一个数字出现 3 次)有种情况。
- 1 个数字出现 5 次,有 10 种情况。
252+840+360+360+90+90+10=2002。
因此,按新思路解决问题的关键在于怎样穷举各数字的出现次数。
【实例 1-5】取数组合
有 0~9 共 10 个数字,现需从这 10 个数字中取出 n 个数字构成一个取数组合,每个数字可以重复取,但不考虑取数顺序。
例如,当 n=3 时,123、132、213、231、312 和 321 均视为同一种取数组合(数字 1、2、3 各取 1 个),而 112(两个 1 和一个 2)和 122(一个 1 和两个 2)是不同的取数组合。
编写程序,输入 n,输出所有的取数组合种数。例如,输入 3,输出 220;输入 5,输出 2002;输入 8,输出 24310。
编程思路 1
定义一个 take 数组来保存 n 位数中每个数字的出现次数。最直接的办法可以编写一个 9 重循环,最外层循环次数从 0~n 用于对 take[0]赋值、第 2 层内循环次数从 0~n-take[0]用于对 take[2]赋值、…、依次类推,最内层循环次数从 0~用于对 take[8]赋值,剩下的次数赋给 take[9]。
源程序 1
#include <iostream>using namespace std;int main(){int n,i,cnt=0,take[10]={0};cin>>n;for (take[0]=0; take[0]<=n; take[0]++){for (take[1]=0; take[1]<=n- take[0]; take[1]++){for (take[2]=0; take[2]<=n- take[1]- take[0]; take[2]++){for (take[3]=0; take[3]<=n- take[2]- take[1]- take[0]; take[3]++){for (take[4]=0; take[4]<=n- take[3]- take[2]- take[1]- take[0]; take[4]++){for (take[5]=0; take[5]<=n- take[4]- take[3]- take[2]- take[1]- take[0]; take[5]++){for (take[6]=0; take[6]<=n- take[5]- take[4]- take[3]- take[2]- take[1]- take[0]; take[6]++){for (take[7]=0; take[7]<=n- take[6]- take[5]- take[4]- take[3]- take[2]- take[1]- take[0]; take[7]++){for (take[8]=0; take[8]<=n- take[7]- take[6]- take[5]- take[4]- take[3]- take[2]- take[1]- take[0]; take[8]++){take[9]=n- take[8]- take[7]- take[6]- take[5]- take[4]- take[3]- take[2]- take[1]- take[0];for (i=0;i<=9;i++)cout<<"i:"<<take[i]<<" ";cout<<endl;cnt++;}}}}}}}}}cout<<"Count="<<cnt<<endl;return 0;}
编程思路 2
上面的思路虽然直接,但按 9 重循环的写法太累赘。实际上,如果将 take 数组从 take[0]~take[9]赋值看出一个依次赋值的过程,那么这个过程可以抽象为一个递归过程。
设函数 DFS(int take[],int index,int leave)表示对数组元素 take[index]赋予 0~leave 之间每个值,则其后会对数组元素 take[index+1]赋予 0~leave- take[index]之间的每个值,即递归地调用函数 DFS(take[], index+1, leave- take[index])。递归的终止条件为 index==10,即 take[0]~take[9]全部赋了值。递归的初始调用为 index=0、leave=n。
源程序 2 及运行结果
#include <iostream>using namespace std;int cnt=0;void DFS(int take[],int index,int leave){int i;if(index==9) // 0~8各数字使用个数列举完成{take[index]=leave; // 剩余的给数字9cnt++; // 有效取数组合,计数return ;}for(i=0;i<=leave;i++){take[index]=i;DFS(take,index+1,leave-i);}}int main(){int n, take[10]={0};cin>>n;DFS(take,0,n);cout<<"Count="<<cnt<<endl;return 0;}
编译并执行以上程序,若输入 5,可得到如下所示的结果。
5Count=2002Press any key to continue
有了上面的取数组合函数 void DFS(int take[],int index,int leave),将 n 位数中 0~9 每个数字出现的次数,存储在 take 数组中后,可以采用循环
sum=0;for (i=0;i<10;i++)sum=sum+take[i]*power(i,lenN);
计算出在当前组合情况下各位数字的 lenN 次方之和 sum。再用函数 Judge 判断 sum 中出现的数字组合情况是否与 take 数组中的组合情况相同,若相同,则就是 n 位花朵数。
采用新思路优化后的源程序如下:
#include <iostream>
#include <ctime>using namespace std;int table[10];int power(int num,int n){int p=1,i;for (i=1;i<=n;i++)p=p*num;return p;}bool Judge(int take[], int sum){int i,a[10]={0};while (sum){ a[sum%10]++;sum/=10;}for(i=0; i<10 && a[i]==take[i];i++);return i==10;}void DFS(int take[],int index,int leave){int i,sum;if(index==9) // 0~8各数字使用个数列举完成{take[index]=leave; // 剩余的给数字9sum=0;for (i=0;i<10;i++)sum=sum+take[i]*table[i];if(Judge(take,sum)){cout<<sum<<" ";} return ;}for(i=0;i<=leave;i++){take[index]=i;DFS(take,index+1,leave-i);}}int main(){int n,i,take[10]={0};cin>>n;int start=clock();for (i=0; i<=9; i++) // 初始化数据表table[i]=power(i,n);DFS(take,0,n); cout<<endl<<"Running Time :"<<clock()-start<<" ms."<<endl;return 0;}
编译并执行以上程序,若输入 9,可得到如下所示的结果。
9534494836 472335975 912985153 146511208Running Time :15 ms.Press any key to continue
从这个执行结果看出,采用新思路优化后的程序的执行效率好很多。
实际上,我们还可以进一步优化。以 5 位花朵数为例,由于 9 的 5 次方等于 59049,因此 9 最多只能在 5 位花朵数中出现 1 次,否则和值会超过 5 位数,因此可以对和值可能超过 5 位数的情况进行剪枝;另外,当小数字用得太多,还可能导致和值的位数达不到,例如 4 的 5 次方为 1024,5 个 4 的 5 次方的和值才 5120,因此若 5 位数全部由 5 以下的数字组成,5 次方之和不可能达到 5 位数,可以直接进行下次搜索,增加大数字的个数。实验验证,经过两次剪枝后,处理的情况为 1329 种,又会大大减少。并且,如果位数越大,采用两次剪枝后的效率越好。例如,求解 8 位花朵数时,0~9 的 8 位取数组合情况有 24310 种,采用剪枝后,处理的情况为 16131 种。
为进行剪枝处理,在当前数字 index 确定了个数 i 后,将 i*indexn 累加到和 sum 中,为此,可以考虑在 DFS 函数中增加一个参数 sum,用于保存当前和。这样,在剪枝处理时可以引用这个和值。
采用剪枝处理后的源程序如下:
#include <iostream>
#include <ctime>using namespace std;int table[12]; // 其中table[10]保存power(10,n),table[11]保存power(10,n-1)int power(int num,int n){int p=1,i;for (i=1;i<=n;i++)p=p*num;return p;}bool Judge(int take[], int sum){int i,a[10]={0};while (sum){ a[sum%10]++;sum/=10;}for(i=0; i<10 && a[i]==take[i];i++);return i==10;}void DFS(int take[],int index,int leave,int sum){int i,tmp,tmp1;if(index==10) // 0~9各数字使用个数列举完成{if(leave>0) return; // 位数不足,直接返回if(Judge(take,sum)){cout<<sum<<" ";} return ;}for(i=0;i<=leave;i++){take[index]=i;tmp=sum+i*table[index];if (tmp>=table[10]) break; // 剪枝1,和值已超过power(10,n)tmp1=tmp+(leave-i)*table[9]; // 剩余的数字全用9的话if(tmp1<table[11]) continue; // 剪枝2,小数字太多,和值不可能达到位数DFS(take,index+1,leave-i,tmp);}}int main(){int n,i,take[10]={0};cin>>n;int start=clock();for (i=0; i<=9; i++) // 初始化数据表table[i]=power(i,n);table[10]=power(10,n);table[11]=power(10,n-1);DFS(take,0,n,0); cout<<endl<<"Running Time :"<<clock()-start<<" ms."<<endl;return 0;}
3、 21 位花朵数
在前面优化程序的基础上,下面我们来解决“蓝桥杯”软件设计大赛的一道比赛题。这是一个大 Boss 哟!
【实例 1-6】21 位花朵数
编写一个程序,输出所有的 21 位花朵数。(注意:这个整数有 21 位,它的各位数字的 21 次方之和正好等于这个数本身。)
编程思路
按照上面的剪枝优化程序的思路,可以求 21 位花朵数。由于 21 位整数超出了 long 整型数的范围,因此采用大整数来处理。定义结构体 BigNum 如下:
struct BigNum
{int dig[4];int len;
};
其中,数组元素 dig[0]~dig[3]分别保存大整数从低位到高位的数字,为节省空间,每个数组元素保存大整数中的 8 位数字。即存储大整数时,从低位到高位每 8 位 1 组,每组保存到一个数组元素中。Len 表示每 8 位 1 组的组数,意即大整数的位数(不过以 8 位为 1 个单位)。
在大整数的基础上,编写如下 6 个函数,来进行大整数的处理。
void Init(BigNum &a); // 大整数a初始化为0
void PrintBigNum(BigNum a); // 输出大整数 a
BigNum CarryUp(BigNum a); // 大整数 a 的处理进位
BigNum Multi(BigNum a,int n); // 大整数 a 和整数 n 相乘
int Cmp(BigNum a,BigNum b); // 大整数a和b比较大小
BigNum Add(BigNum a,BigNum b);// 大整数a 和 b 相加
另外,由于求 1 个数字的 21 次方也较耗时。为了减少程序运行时间,可以先把 0~9 的 21 次方及其不同的出现次数的值先算出来,存储到指定的数组中。
定义数组 BigNum pow[10]; ,其中 pow[i](0<=i<=9)存储数字 i 的 21 次方。
定义数组 BigNum sp[10][22]; ,其中 sp[i][j] 存储数字 i 的 21 次方乘以 j(出现次数)得到的值。
这样,程序中需要用到这些值时,可直接引用相应数组元素的值,从而最多只需计算 10 个大数连加(想想为什么?),无需计算求幂和乘法,大大节约时间。
源程序及运行结果
#include <iostream>
#include <ctime>using namespace std;const int BIT=100000000; // 每8位一组struct BigNum{int dig[4];int len;};BigNum pow[10],MAX,MIN;BigNum sp[10][22];int take[10]={0};int LEN=21;void Init(BigNum &a){a.len=1;for (int i=0;i<4;i++)a.dig[i]=0;}void PrintBigNum(BigNum a){int i;cout<<a.dig[a.len-1];for(i=a.len-2; i>=0; i--){cout.fill('0'); // 定义填充字符'0'cout.width(8); cout<<a.dig[i];}cout<<endl;}BigNum CarryUp(BigNum a) // 处理进位{int i;for(i=0;i<a.len;i++){a.dig[i+1]+=a.dig[i]/BIT;a.dig[i]%=BIT;}return a;}BigNum Multi(BigNum a,int n){BigNum c;int i;Init(c);c.len=a.len+1;for(i=0;i<a.len;i++){c.dig[i]=(a.dig[i])*n;}c=CarryUp(c);if(c.len>0 && c.dig[c.len-1]==0)c.len--;return c;}int Cmp(BigNum a,BigNum b){if(a.len>b.len) return 1;if(a.len<b.len) return -1;int i;for(i=a.len-1;i>=0 && a.dig[i]==b.dig[i];i--);if(i==-1) return 0;return a.dig[i]-b.dig[i];}BigNum Add(BigNum a,BigNum b){int i;if(b.len>a.len) a.len=b.len;for(i=0;i<a.len;i++){a.dig[i]+=b.dig[i];}a=CarryUp(a);if(a.dig[a.len]) a.len++;return a;}bool Judge(BigNum sum){int aa[10]={0};int i,j;for(i=1;i<=8;i++) // 求 sum 中0~9各个数字出现的次数,保存到数组aa中 for (j=0;j<3; j++){aa[sum.dig[j]%10]++;sum.dig[j]/=10;}aa[0]=aa[0]-3;for(i=0; i<10 && aa[i]==take[i];i++);return i==10;}void DFS(int deep,BigNum Sum,int leave){BigNum check;BigNum cc;int i;if(deep==10){if(leave>0)return;if(Judge(Sum)){PrintBigNum(Sum);}return ;}for(i=0;i<=leave;i++){take[deep]=i;check=Add(Sum,sp[deep][i]);if(Cmp(check,MAX)>=0) break; // 剪枝1cc=Add(check,sp[9][leave-i]);if(Cmp(cc,MIN)<0) continue; // 剪枝2DFS(deep+1,check,leave-i);}}int main(){int start=clock(); int i, j;BigNum sum;Init(pow[0]);for(i=1;i<10;i++){Init(pow[i]); pow[i].dig[0]=1;for (j=1;j<=21;j++)pow[i]=Multi(pow[i],i);}for(i=0;i<10;i++)Init(sp[i][0]);for(j=0;j<10;j++)for(i=1;i<22;i++){sp[j][i]=Add(sp[j][i-1],pow[j]);}Init(sum);MAX.dig[2]=100000; MAX.len=3;MIN.dig[2]=10000; MIN.len=3;DFS(0,sum,LEN);cout<<endl<<"Running Time :"<<clock()-start<<" ms."<<endl;return 0;}
编译并执行以上程序,得到如下所示的结果。
128468643043731391252449177399146038697307Running Time :32046 ms.Press any key to continue
在进行程序设计实践时,一定不能就题论题,而应该贯穿着“连营”和“集智”。在这个实践过程中,有提出问题、解决问题、扩展问题、再解决问题、对解决问题的方法评价、优化设计等几个环节,实际上是一个螺旋式滚动向前的过程,在这个螺旋式不断向前的过程中,能够非常自然地调动程序设计学习者的学习兴趣,而且通过问题的不断扩展“连营”,有效地开阔读者的思维。这种通过一个程序的层层推进,不断连营,进行程序设计训练的方法,本质上是一个循序渐进、螺旋式上升的过程,可使学习者在“走台阶”的过程中,进入到程序设计的殿堂。
相关文章:
基于C++实现水仙花数
1、水仙花数的连营 1.1、水仙花数 在学习程序设计课程时,大多数读者一定采用循环结构编写过求解水仙花数的程序。 【实例 1-1】水仙花数 一个三位整数(100~999),若各位数的立方和等于该数自身,则称其为“…...
关于一个类中引用两外一个类中的变量和方法,一个技巧可以提高开发效率
import static com.xx.xx.util.ext.xx.toJson; import static com.xx.xx.util.ext.smf.Cert.certMgrClient; 第一个引用一个方法,第二个引用一个变量, 引用后就可以直接通过变量名或者方法名就行使用,很方便,不要通过class.方式调…...

算法笔记:OPTICS 聚类
1 基本介绍 OPTICS(Ordering points to identify the clustering structure)是一基于密度的聚类算法 OPTICS算法是DBSCAN的改进版本 在DBCSAN算法中需要输入两个参数: ϵ 和 MinPts ,选择不同的参数会导致最终聚类的结果千差万别,因此DBCSAN…...

SSRF漏洞防御:黑白名单的编写
文章目录 SSRF漏洞防御:黑白名单的编写黑名单的制作白名单的制作 SSRF漏洞防御:黑白名单的编写 以pikachu靶场中SSRF(crul)为例我们可以看到未做任何防御 我们查看源代码 黑名单的制作 思路: 什么内容不能访问 构造代码 $xyarray("file" > "",&q…...
想要对网站进行安全监测,安全SCDN效果怎么样?
随着互联网的迅速成长,各种网站出现的越来越多,个人网站、企业网站等,同时网站竞争也越来越强。随着用户对网站需求增多,对网站的安全也愈发受到人们的重视。那么我们日常网站运营中,有需要对网站进行安全监控…...
操作符extends的作用是什么?
在TypeScript中,extends关键字用于创建类之间的继承关系。它允许一个类(子类)继承另一个类(父类)的属性和方法,并可以在子类中添加新的属性和方法或者修改继承自父类的属性和方法。 extends的作用是实现类…...

跟着chatgpt一起学|1.spark入门之MLLib
chatgpt在这一章表现的不好,所以我主要用它来帮我翻译文章提炼信息 1.前言 首先找到spark官网里关于MLLib的链接 spark内一共有2种支持机器学习的包, 一种是spark.ml,基于DataFrame的,也是目前主流的 另一种则是spark.mllib,是基于RDD的…...
JAVA后端开发技术报告
JAVA后端开发技术报告 一、引言 随着互联网技术的不断发展,JAVA作为一门成熟的后端开发语言,应用范围广泛。本报告旨在介绍JAVA后端开发的相关技术,包括JAVA语言基础、Spring框架、数据库技术以及性能优化等方面,帮助开发者更好…...

销售心理学 如何了解客户的购买心理激发客户购买兴趣
销售心理学 如何了解客户的购买心理激发客户购买兴趣 在销售的世界里,掌握客户的购买心理,如同一把神奇的钥匙,能够解锁客户内心的需求和兴趣。如何巧妙地运用销售心理学,激发客户的购买欲望呢?以下是一些建议&#x…...
霍夫丁不等式(Hoeffding‘s inequality)
参考资料:Hoeffdings inequality | encyclopedia article by TheFreeDictionary 霍夫丁不等式(Hoeffdings inequality)描述了随机变量的和、与和的期望之差的上限;或者表述为:随机变量的均值、与均值的期望之差的上限。…...

【MATLAB源码-第90期】基于matlab的OQPSKsimulink仿真,对比初始信号和解调信号输出星座图。
操作环境: MATLAB 2022a 1、算法描述 正交偏移二进制相移键控(OQPSK, Orthogonal Quadrature Phase Shift Keying)是一种数字调制技术,主要用于高效无线数据传输。它是传统二进制相移键控(BPSK)的一个变…...
自动驾驶芯片指标AI算力TOPS和CPU算力DMIPS
自动驾驶芯片指标AI算力TOPS和CPU算力DMIPS 文章目录 自动驾驶芯片指标AI算力TOPS和CPU算力DMIPS智能驾驶芯片CPU GPU NPU算力单位TOPS乘积累加运算MACTOPS计算公式GPU算力TFLOPSTFLOPS与TOPS的换算CPU算力DMIPS 智能驾驶芯片 根据地平线数据, L2级自动驾驶的算力…...

海外Leads Generation产业:中国出海群体的行业大机会
Leads Generation(简称LeadsGen)指的是集中精力吸引和开发潜在客户的营销策略。通过引导式的营销策略,企业分发内容吸引潜在客户,引导客户留下电话/邮件/姓名等信息。基于这些信息,企业可建立潜在客户数据库࿰…...

SQL sever2008中的游标
目录 一、游标概述 二、游标的实现 三、优缺点 3.1优点: 3.2缺点: 四、游标类型 4.1静态游标 4.2动态游标 4.3只进游标 4.4键集驱动游标 4.5显示游标: 4.6隐式游标 五、游标基本操作 5.1声明游标 5.1.1.IS0标准语法 5.1.1.1语…...
在linux中进行文件的打包(打压缩)和解压
1.".tar " 格式(打包不会压缩) ".tar" 格式的打包和解打包都使用 tar 命令,区别只是选项不同。 ".tar" 格式打包命令: tar [选项] [-f 压缩包名] 源文件或目录 选项: -cÿ…...

mysql8下载与安装教程
文章目录 1. MySQL下载2. 方式一:msi文件安装2.1 安装2.2 添加环境变量2.3 登录mysql 3. 方式二:zip文件安装3.1 安装3.2 配置文件3.3 加入环境变量3.4 初始化mysql3.5 登录mysql 1. MySQL下载 以下两个网址二选一 官网:https://downloads.…...

ubuntu22.04在线安装redis,可选择版本
安装脚本7.0.5版本 在线安装脚本,默认版本号是7.0.5,可以根据需要选择需要的版本进行下载编译安装 sudo apt-get install gcc -y sudo apt-get install pkg-config -y sudo apt-get install build-essential -y#安装redis rm -rf ./tmp.log systemctl …...
MYSQL加密和压缩函数详解和实战(含示例)
MySQL提供了多种加密和压缩方式,可以帮助保护数据库中的敏感数据。以下是一些常见的MySQL加密和压缩方法参考: 建议收藏以备后续用到查阅参考。 目录 一、AES_ENCRYPT AES加密 二、AES_DECRYPT AES解密 三、COMPRESS 压缩字符串 四、UNCOMPRESS 解压…...

redis Redis::geoAdd 无效,phpstudy 如何升级redis版本
redis 查看当前版本命令 INFO SERVERwindows 版redis 进入下载 geoadd 功能在3.2之后才有的,但是phpstudy提供的最新的版本也是在3.0,所以需要升级下 所以想出一个 挂狗头,卖羊肉的方法,下载windows 的程序,直接替…...

2024重庆大学计算机考研分析
24计算机考研|上岸指南 重庆大学 重庆大学计算机考研招生学院是计算机学院和大数据与软件学院。目前均已出拟录取名单。 重庆大学计算机学院是我国高校最早开展计算机研究的基地之一,1978年和1986年获西南地区首个硕士和博士点,1998年成立计算机学院&a…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...