基于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 种情形:

  1. 5 位数中每个数字只出现 1 次(即 1+1+1+1+1),有种情况。
  2. 5 位数中 1 个数字出现 2 次、另 3 个数字各出现 1 次(即 1+1+1+2),有种情况。
  3. 1+2+2(即 1 个数字出现 1 次,一个数字出现 2 次,还有一个数字出现 2 次)有种情况。
  4. 1+1+3(即 1 个数字出现 1 次,另一个数字也出现 1 次,还有一个数字出现 3 次)有种情况。
  5. 1+4(即 1 个数字出现 1 次,另一个数字出现 4 次)有种情况。
  6. 2+3(即 1 个数字出现 2 次,另一个数字出现 3 次)有种情况。
  7. 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

在进行程序设计实践时,一定不能就题论题,而应该贯穿着“连营”和“集智”。在这个实践过程中,有提出问题、解决问题、扩展问题、再解决问题、对解决问题的方法评价、优化设计等几个环节,实际上是一个螺旋式滚动向前的过程,在这个螺旋式不断向前的过程中,能够非常自然地调动程序设计学习者的学习兴趣,而且通过问题的不断扩展“连营”,有效地开阔读者的思维。这种通过一个程序的层层推进,不断连营,进行程序设计训练的方法,本质上是一个循序渐进、螺旋式上升的过程,可使学习者在“走台阶”的过程中,进入到程序设计的殿堂。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/173345.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SAP创建ODATA服务-Structure

SAP创建ODATA服务-Structure 1、创建数据字典 进入se11创建透明表ZRICO_USR,并创建对应字段 2、创建OData service 首先创建Gateway service project&#xff0c;事务码&#xff1a;SEGW&#xff0c;点击Create Project 按钮 Gateway service Project分四个部分&#xff1a…

JVS-rules规则引擎导出与导入,确保业务连续性的关键

在复杂的系统环境中&#xff0c;规则和配置的迁移、备份及共享成为了确保业务连续性和一致性的关键过程。不同的环境可能需要相同的规则和配置数据&#xff0c;或者我们可能需要备份这些数据以防万一。JVS规则引擎提供了规则的导出与导入功能&#xff0c;使用户能够在多个环境间…

机器学习的复习笔记2-回归

一、什么是回归 机器学习中的回归是一种预测性分析任务&#xff0c;旨在找出因变量&#xff08;目标变量&#xff09;和自变量&#xff08;预测变量&#xff09;之间的关系。与分类问题不同&#xff0c;回归问题关注的是预测连续型或数值型数据&#xff0c;如温度、年龄、薪水…

规则引擎Drools使用,0基础入门规则引擎Drools(四)WorkBench控制台

文章目录 系列文章索引八、WorkBench简介与安装1、WorkBench简介2、安装 九、WorkBench使用方式1、创建空间2、创建项目3、创建数据对象4、创建DRL规则文件5、创建测试场景6、设置KieBase和KieSession7、编译、构建、部署8、在项目中使用部署的规则 系列文章索引 规则引擎Droo…

电商数据采集及数据监测的关注重点

当品牌需要做分析报告时&#xff0c;需要用到电商数据&#xff0c;所以分析的前提是数据采集&#xff0c;只有采集的数据越准确&#xff0c;分析的报告才有价值&#xff0c;同样&#xff0c;品牌在做数据监测的基础也是采集&#xff0c;如电商价格监测&#xff0c;需要采集到准…

编译器设计03-后端概述

后端处理概述 后端处理&#xff1a;中间代码生成&#xff0c;目标代码生成&#xff0c;贯穿各个阶段的优化。 后端处理犹如得出中文文章&#xff0c;当阅读完英语文章后&#xff0c;你的脑海中就有清晰的“中间代码”了&#xff0c;想写作的时候就心中有数&#xff0c;核心论…

全面探讨HTTP协议从0.9到3.0版本的发展和特点

前言&#xff1a; 最近的几场面试都问到了http的相关知识点&#xff0c;博主在此结合书籍和网上资料做下总结。本篇文章讲收录到秋招专题&#xff0c;该专栏比较适合刚入坑Java的小白以及准备秋招的大佬阅读。 如果文章有什么需要改进的地方欢迎大佬提出&#xff0c;对大佬有帮…

Ubuntu安装Vmtools (最新安装教程)

Ubuntu安装Vmtools 1. 设置root用户密码2. 切换root用户3. 安装vmools 1. 设置root用户密码 出现认证失败&#xff08;Authentication failure&#xff09;的原因有两种&#xff0c;要么是密码输入错误&#xff0c;要么是新安装的系统还没有给root设置密码&#xff0c;&#x…

NX二次开发UF_CURVE_ask_line_data 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_line_data Defined in: uf_curve.h int UF_CURVE_ask_line_data(tag_t line, UF_CURVE_line_p_t line_coords ) overview 概述 Returns the coordinates of a line w…

js基础知识

1. beforeCreate 初始化界面前 : 在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问。 2. created 初始化界面后 : 在实例创建完成后发生&#xff0c;当前阶段已经完成了数据观测&#xff0c;也就是可以使用数据&#xff0c;更改数据&#xff0c;在这里更…

7天用Go实现Web框架Gee教程

本文是学习模仿自https://geektutu.com/post/gee.html 在此基础上&#xff0c;加入自己的学习过程与理解 框架 设计框架之前&#xff0c;需要知道为什么需要使用框架&#xff0c;框架能解决什么问题。只有明白了这一点&#xff0c;才能设计出框架中的功能。 通俗来讲&#…

基于springboot实现实习管理系统的设计与实现项目【项目源码+论文说明】

基于sprinmgboot实现实习管理系统的设计与实现演示 摘要 随着信息化时代的到来&#xff0c;管理系统都趋向于智能化、系统化&#xff0c;实习管理也不例外&#xff0c;但目前国内仍都使用人工管理&#xff0c;市场规模越来越大&#xff0c;同时信息量也越来越庞大&#xff0c;…

Unity 关于Input类的使用

Input类在我们游戏开发中需要获取外设设备&#xff08;比如键盘、鼠标、游戏手柄等&#xff09;进行交互时&#xff0c;基本都会用到。 它主要有以下一些常用的方法。 1、GetKey(KeyCode key)&#xff0c;检测按键是否被按下&#xff1b; 2、GetKeyDown(KeyCode key)&#x…

ubuntu2204 防火墙ufw限制某ip对某端口的访问

公司内部有个ip为10.10.10.1的网关&#xff0c;每天定时端口扫描&#xff0c;然后扫描发送的数据包http server解析不了&#xff0c;日志里就会记录这个错误&#xff0c;有点烦&#xff0c; 用防火墙过滤一下 ubuntu的防火墙命令是 ufw&#xff0c; 跟ufo挺像的&#xff0c;也…

基于helm的方式在k8s集群中部署gitlab - 升级(三)

接上一篇 基于helm的方式在k8s集群中部署gitlab - 部署&#xff08;一&#xff09;&#xff0c;本篇重点对gitlab在k8s集群中进行升级 文章目录 1. gitlab 升级1.1 获取release1.2 下载目前版本的gitlab charts1.3 获取当前的values文件1.4 升级 2. gitlab数据库升级2.1 备份数…

SSRF漏洞防御:黑白名单的编写

文章目录 SSRF漏洞防御:黑白名单的编写黑名单的制作白名单的制作 SSRF漏洞防御:黑白名单的编写 以pikachu靶场中SSRF(crul)为例我们可以看到未做任何防御 我们查看源代码 黑名单的制作 思路: 什么内容不能访问 构造代码 $xyarray("file" > "",&q…

rdf-file:读写示例

<dependency><groupId>com.alipay.rdf.file</groupId><artifactId>rdf-file-core</artifactId><version>2.2.10</version> </dependency>一&#xff1a;读 一&#xff1a;写 写文件之正常写 协议布局模板 使用内置的布局文…

关于一个类中引用两外一个类中的变量和方法,一个技巧可以提高开发效率

import static com.xx.xx.util.ext.xx.toJson; import static com.xx.xx.util.ext.smf.Cert.certMgrClient; 第一个引用一个方法&#xff0c;第二个引用一个变量&#xff0c; 引用后就可以直接通过变量名或者方法名就行使用&#xff0c;很方便&#xff0c;不要通过class.方式调…

maven中scope和optional区别

文章目录 1. Scope&#xff08;作用范围&#xff09;&#xff1a;2. Optional&#xff08;可选项&#xff09;&#xff1a; 1. Scope&#xff08;作用范围&#xff09;&#xff1a; Maven的<scope>元素用于指定依赖项的作用范围&#xff0c;即依赖项在构建和运行时的可见…

【人工智能】它正在悄悄改变我的学习与生活,并试图改变我的全部!

前言 人工智能对我们的生活影响有多大&#xff1f;作为一名计算机研一的学生&#xff0c;一开学&#xff0c;学习使用ChatGTP便是我的第一个堂课。&#xff08;主要用于做作业&#x1f602;&#xff09; 我的本科毕业论文是在计算机视觉&#xff08;CV&#xff09;方向进行的…