第D练——数学之美
1. 数学之美 1.1. 水仙花数:Narcissistic.cpp(本题30分) 【题目描述】 输入整数n,输出第n小的“水仙花数”。所谓的“水仙花数”是指一个m位正整数,其各位数字的m次方之和等于该数本身。例如:8是一个“水仙花数”,因为8=81(8的一次方);153也是一个“水仙花数”,因为153=13+53+33(1的三次方+5的三次方+3的三次方)。
【程序分析】
利用while循环控制自1开始逐个正整数进行“水仙花数”测试。首先,获得数值的位数和各个数位上的数字。然后,进行是否为水仙花数的判断,若是则计数加1;否则进行下一个正整数的“水仙花数”测试。
循环此过程,直到找到第n个“水仙花数”。
【输入】
输入文件Narcissistic.in有1行,包含1个int类型的整数,即输入的变量n。
【输出】
输出文件Narcissistic.out有1行,包含1个int类型的整数,即第n个“水仙花数”。
【输入输出样例1】
Narcissistic.in Narcissistic.out
12 371
【输入输出样例2】
Narcissistic.in Narcissistic.out
18 92727
【数据限制】
1≤n≤20。
#include<stdio.h>
int digit[20]; //一个正整数的个、十、百、千、万……位上的数字字符
/*函数功能: 返回给定数值的位数(宽度),并将给定数值的个、十、百、千、万……位上的数字字符按 "低位到高位"的顺序从左到右存储在数组digit[.]中*/
int digitNum(int dn){
//(1)返回给定数值的位数(宽度),并将给定数值的个、十、百、千、万……位上的数字字符存储在
int w=0;//dn-给定的数字; w-给定的数字的位数(宽度)
while( dn != 0 ){
digit[w] = dn%10; //(A)获得[当前数值dn]的个位数
w++; //(B)[原始数值dn]的位数(宽度)+1
dn /=10; //(C)[当前数值dn]去除个位数
}
//(2)返回此数dn的位数(宽度)
return w;
}
/*函数功能: 求给定的数值num的n次方*/
int cifang(int num, int n){
int result = num;
for(int i=0; i<n-1; i++){
result *= num;
}
return result;
}
int main() {
int n, count = 0; //n-变量,表示想获得第n个水仙花数; count-目前找到的'水仙花数'的数目
int i = 0; //i-循环变量,表示待测试的(正)整数
int w; //w-数位宽度,表示整数i的数位宽度
printf("请输入想获得的水仙花数的序号(n):");
FILE *fp;
if((fp=fopen("Narcissistic.in", "r")) != NULL ){
fclose(fp); //存在的话,要先把之前打开的文件关掉
freopen("Narcissistic.in", "r", stdin);
freopen("Narcissistic.out", "w", stdout);
}
scanf("%d", &n); //输入想获得的水仙花数的序号
//*************************************
while(++i) { //for(i=100; i<1000; i++) {
//(1)获得数值i的数位宽度w, 并将个、十、百、千、万……位上的数字字符按 "低位到高位"的顺序从左到右存储在数组digit[.]中
w = digitNum(i);
//(2)将数值i的w个数位上的数字分别进行w次方,并求和
int sum = 0;
for(int k=0; k<w; k++){
//sum += power(digit[k], w); //数位digit[k]求w次方,并累加到总和sum中
sum += cifang(digit[k], w); //数位digit[k]求w次方,并累加到总和sum中
}
//(3)若数值i的w个数位上数字的w次方的总和==(等于)i, 则为水仙花数! 并累加水仙花数 计数, 若已找到第n个,则输出,并退出循环
if(i == sum){
//(3.1)水仙花数的计数+1
count++;
//(3.2)总共已经寻找到n个水仙花数,则输出次水仙花数, 并退出循环
if(count == n){
printf("%d", i); //第n个水仙花数-i
break;
}
}
}
//=====================================
return 0;
}
1.2. 完备数:PerfectNumber.cpp(本题30分) 【题目描述】 输入整数n,输出从小到大有序的第n个完备数及其因子信息。所谓的“完备数”是指一个数如果恰好等于它的因子之和,则这个数称为“完备数”。例如,6=1+2+3。
【程序分析】
利用while循环进行正整数遍历和退出条件控制;利用for循环进行某个整数的因子(整除数)搜索。
【输入】
输入文件PerfectNumber.in有1行,包含1个int类型的整数,即输入的变量n。
【输出】
输出文件PerfectNumber.out有1行,包含1个等式,即从小到大有序的第n个完备数及其因子信息。
【输入输出样例1】
PerfectNumber.in PerfectNumber.out
1 6=1+2+3
【输入输出样例2】
PerfectNumber.in PerfectNumber.out
2 28=1+2+4+7+14
【数据限制】
1≤n≤4。
#include<stdio.h>
int main(){
int n, pefectCount, i; //n-完备数序号; pefectCount-完备数计数; i-遍历的循环变量
int num, sum; //num-待测试是否为完备数的数值; sum-某个数num的因子和;
int factors[100]; //数num的因子
int factorNum; //数num的因子个数
printf("请输入待获得的完备数的序号(n):");
FILE *fp;
if((fp=fopen("PerfectNumber.in", "r")) != NULL ){
fclose(fp); //存在的话,要先把之前打开的文件关掉
freopen("PerfectNumber.in", "r", stdin);
freopen("PerfectNumber.out", "w", stdout);
}
scanf("%d", &n);
//********************************************
//(1)初始化pefectCount和num
pefectCount = 0; //完备数计数
num = 1; //初始化待测试后的‘潜在完备数’(num从1开始...)
//(2)num从1开始,测试后数值num是否为完备数?
while(num++ && pefectCount < n){
//(2.1)初始化sum和factorNum
sum = 0; //初始化:因子的总和=0
factorNum = 0; //初始化:因子的数目=0
//(2.2)从1开始遍历(至num-1), 寻找num的因子
for(i=1; i<num; i++){
if(num%i == 0){//能整除,k是因子
//(a)累加当前因子k
sum += i;
//(b)记录第factorNum个因子
factors[factorNum] = i;
//(c)因子个数factorNum+1
factorNum++;
//(d)如果数i的因子和已经超过数i自身,则直接跳过,不可能是完备数
if( sum > num ){
break;
}
}
}
//(2.3)如果num的因子之和sum恰好等于数num,则num为完备数
if( sum == num ){
pefectCount++; //
}
//(2.4)如果已经找到第n个完备数,则按要求输出该完备数的信息,并退出程序
if(pefectCount == n){
//(a)输出数值
printf("%d=", num);
//(b)输出所有因子
for(i=0; i<factorNum-1; i++){
printf("%d+", factors[i]);//输出因子信息
}
printf("%d", factors[factorNum-1]);
}
}
//============================================
return 0;
}
1.3. 回文数:Plalindrome.cpp(本题20分) 【题目描述】 输入整数n,判断整数n是否为回文数,是则输出YES,否则输出NO。例如,五位数12321是回文数,四位数1234不是回文数。
【程序分析】
学会分解出每一位数。
【输入】
输入文件Plalindrome.in有1行,包含1个long类型的整数,即输入的变量n。
【输出】
输出文件Plalindrome.out有1行,包含1个单词“YES”或“NO”,即是否为回文数。
【输入输出样例1】
Plalindrome.in Plalindrome.out
123454321 YES
【输入输出样例2】
Plalindrome.in Plalindrome.out
1690 NO
【数据限制】
1≤x≤1012。
#include<stdio.h>
int digit[50]; //一个正整数的个、十、百、千、万……位上的数字字符
/*函数功能: 返回给定数值的位数(宽度),并将给定数值的个、十、百、千、万……位上的数字字符按 "低位到高位"的顺序从左到右存储在数组digit[.]中*/
int digitNum(long dn){
//(1)返回给定数值的位数(宽度),并将给定数值的个、十、百、千、万……位上的数字字符存储在
int w=0;//dn-给定的数字; w-给定的数字的位数(宽度)
//********************************************
while( dn != 0 ){
digit[w] = dn%10; //(A)获得[当前数值dn]的个位数
w++; //(B)[原始数值dn]的位数(宽度)+1
dn /=10; //(C)[当前数值dn]去除个位数
}
//============================================
//(2)返回此数dn的位数(宽度)
return w;
}
int main(){
long n; //给定的整数
int w; //w-数位宽度,表示整数n的数位宽度;
int i, flag; //i-判断是否回文时的循环变量; flag-是否为回文数的标识(1-是, 0-否)
printf("请输入待判断是否为回文数的正整数(n):");
FILE *fp;
if((fp=fopen("Plalindrome.in", "r")) != NULL ){
fclose(fp); //存在的话,要先把之前打开的文件关掉
freopen("Plalindrome.in", "r", stdin);
freopen("Plalindrome.out", "w", stdout);
}
scanf("%ld", &n); //输入正整数n //scanf("%ld",&x);
//********************************************
//(1)初始化是否回文标识,默认将数n视为 回文!
flag = 1;
//(2)获得数值n的数位宽度w, 并将个、十、百、千、万……位上的数字字符按 "低位到高位"的顺序从左到右存储在数组digit[.]中
w = digitNum(n);
//(3)从数位两头往中间收缩,判断数字是否相同,一旦发现不同,则不是回文数
for(i=0; (i<w) && (i<w-1-i); i++){
if(digit[i] != digit[w-1-i]){//如果'两头(首-尾)'不相同,则不是回文数
flag = 0;
break;
}
}
//(4)根据是否回文标识flag,按要求输出结果信息
if(flag){//flag==1 是回文数
printf("YES");
}else{ //不是回文数
printf("NO");
}
//============================================
return 0;
}
1.4. 重复数:RegularNumber.cpp(本题20分) 【题目描述】 给定1-9之间的数字a和整数n,求和 (共有n个数相加)的值。例如,a=2,n=5时,和s=2+22+222+2222+22222=24690。
【程序分析】
解本题的关键是计算出每一项的值。
【输入】
输入文件RegularNumber.in有1行,包含2个数,第1个数是1-9之间的数字(即a),第2个数是一个整数(即n)。
【输出】
输出文件RegularNumber.out有1行,包含1个long类型的整数,即和s。
【输入输出样例1】
RegularNumber.in RegularNumber.out
2 5 24690
【输入输出样例2】
RegularNumber.in RegularNumber.out
5 8 61728390
【数据限制】
1≤a≤9,1≤n。
#include<stdio.h>
long sum(int a, int n){
long int sn, tn; //sn-n个项的和;tn-某个项
int count = 1; //count-表示累加了n项中的第count项
//********************************************
/**方法(一)*/
sn = 0;
tn = a;
while(count <= n){
//(A)累加当前项tn
sn += tn;
//(B)下一项
tn = tn*10 + a;
//(C)项数+1
count++;
}
/**方法(二)
sn = 0;
tn = 0;
while(count <= n){
//(A)
tn = tn + a;
//(B)
sn = sn + tn;
//(C)
a = a*10;
//(D)项数+1
++count;
}
*/
//============================================
//返回和sn
return sn;
}
int main() {
int a, n; //a-{1-9}之间的数字; n-和的项数(一个整数)
long int s; //s-n项总和
printf("请输入a和n的值:");
FILE *fp;
if((fp=fopen("RegularNumber.in", "r")) != NULL ){
fclose(fp); //存在的话,要先把之前打开的文件关掉
freopen("RegularNumber.in", "r", stdin);
freopen("RegularNumber.out", "w", stdout);
}
scanf("%d%d", &a, &n); //输入a和n的值
//printf("a=%d, n=%d!\n", a, n);
//********************************************
s = sum(a, n); //调用函数sum获得n项和s
//============================================
printf("%ld", s); //输出n项和s //printf("a+aa+...=%ld\n", sn);
return 0;
}