一.判别m是否为素数
1.概念: 一个数m,如果仅能被1和m整除,则m为素数(质数).
2.理解: 如果m能够被2到m-1间的任意一个数整除,m就不是素数
二.朴素的算法
#include <stdio.h>
int main()
{
int m, is_prime = 1;
scanf_s("%d", &m);
for (int i = 2; i <= m - 1; i++)
{
if (m % i == 0)
{
is_prime = 0;
break;
}
}
if (is_prime == 0)
{
printf("%d不是素数\n", m);
}
else printf("%d是素数\n", m);
}
三.改进减少循环次数
原理: 因子的对称性
72 = 2 × 36
72 = 3 × 24
72 = 4 × 18
72 = 6 × 12
72 = 8 × 9
72 = 9 × 8
72 = 12 × 6
72 = 18 × 4
72 = 24 × 3
72 = 36 × 2
#include <stdio.h>
#include <math.h>
int main()
{
int m, k, is_prime = 1;
scanf_s("%d", &m);
k = sqrt(m);
for (int i = 2; i <= k; i++)//最多循环到k
{
if (m % i == 0)
{
is_prime = 0;
break;
}
}
if (is_prime == 0)
{
printf("%d不是素数\n", m);
}
else printf("%d是素数\n", m);
}
四.找出100~200间的全部素数
#include <stdio.h>
#include <math.h>
int main()
{
int m, k, is_prime = 1,n=0;
for (m = 101; m <= 200; m += 2)//偶数不是素数
{
is_prime = 1;
k = sqrt(m);
for(int i=2;i<=k;i++)//最多循环到k
if (m % i == 0)
{
is_prime = 0;
break;//及时退出
}
if (is_prime == 1)
{
printf("%d\t", m);
++n;
if (n % 5 == 0)
printf("\n");
}
}
}
五.实践项目
【项目1-完数】
一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如6=1+2+3,再如8的因子和是7(即1+2+4),8不是完数。
(1)输入一个数n,判断n是否是完数
解法1:常规解法
#include <stdio.h>
int main()
{
int n, m, s = 1; //n为完数,m为n的因子,s为因子的和;
printf("输入数n: ");
scanf_s("%d", &n);
for (m = 2; m < n; m++)
{
if (n % m == 0)
{
s += m;
}
}
if (n == s)
{
printf("YES!\n");
printf("%d=1",n);
for ( m = 2; m < n; m++)
{
if (n % m == 0)
{
printf("+%d", m);
}
}
}
else
{
printf("NO!\n");
}
printf("\n");
}
解法2:利用因子对称性降低循环次数
#include <stdio.h>
#include <stdio.h>
#include <math.h>
int main()
{
int n, m, s = 1; //n为完数,m为n的因子,s为因子的和;
printf("输入数n: ");
scanf_s("%d", &n);
for (m = 2; m < sqrt(n); m++) //利用因子的对称性
{
if (n % m == 0)
{
s += m + n / m;
}
}
printf("m=%d\n", m); //测试m值用,此时m已被for循环中m++赋值
if (m * m == s) //若m=sqrt(n)时,s需要在加上一个m值;
{
s += m;
}
if (n == s)
{
printf("YES!\n");
printf("%d=1", n);
for (m = 2; m < sqrt(n); m++)
{
if (n % m == 0)
{
printf("+%d+%d", m, n / m);
}
}
if (m * m == s) //若m=sqrt(n)时,s需要在加上一个m值;
{
printf("+%d", m);
}
}
else
{
printf("NO!\n");
}
printf("\n");
}
(2)输出1000以内的所有完数
#include <stdio.h>
#include <math.h>
int main()
{
int n,m, s; //n为完数,m为n的因子,s为因子的和;
printf("1000以内的完数: ");
for ( n = 2; n <= 1000; n++)//1不算完数
{
s = 1;//每次计算s要初始化为1;
for (m = 2; m < sqrt(n); m++) //利用因子的对称性
{
if (n % m == 0)
{
s += m + n / m;
}
}
if (m * m == s) //若m=sqrt(n)时,s需要在加上一个m值;
{
s += m;
}
if (n == s)
{
printf("%d, ", n);
}
}
printf("\n");
}
运行结果:
1000以内的完数: 6, 28, 496,
(3)亲密数:如果整数A的全部因子(包括1,不包括A本身)之和等于B;且整数B的全部因子(包括1,不包括B本身)之和等于A,则将整数A和B称为亲密数。求3000以内的全部亲密数。(提示:按照亲密数定义,要判断数a是否有亲密数,只要计算出a的全部因子的累加和为b,再计算b的全部因子的累加和为n,若n等于a则可判定a和b是亲密数。)
#include <stdio.h>
#include <math.h>
int main()
{
int a, b, n, m;
printf("3000以内的亲密数: \n");
for (a = 2; a <= 3000; a++)
{
b = 1;
for (m = 2; m < sqrt(a); m++)
{
if (a % m == 0)
{
b += m + a / m;
}
}
if (m * m == a)
{
b += m;
}
n = 1;
for (m = 2; m < sqrt(b); m++)
{
if (b % m == 0)
{
n += m + b / m;
}
}
if (m * m == b)
{
n += m;
}
if (n == a && a != b && a < (a + b) / 2)
printf("%d\t%d\n", a, b);
}
}
运行结果:
3000以内的亲密数:
220 284
1184 1210
2620 2924
【项目2 - n=a!+b!+c!】
求满足条件n=a!+b!+c!的所有三位数n并输出,其中a,b,c分别为n的个、十、百位数。

解法一:
#include <stdio.h>
int main()
{
int a, b, c, x, i, suma, sumb, sumc;
for (x = 100; x < 1000; x++)
{
a = x % 10;
b = x / 10 % 10;
c = x / 100;
suma = 1;
sumb = 1;
sumc = 1;
for (i = 1; i <= a; i++) //求a!
{
suma *= i;
}
for (i = 1; i <= b; i++) //求b!
{
sumb *= i;
}
for (i = 1; i <= c; i++) //求c!
{
sumc *= i;
}
if (x == suma + sumb + sumc)
{
printf("%d\n", x);
}
}
}
运行结果:
145
解法二:优化降低循环次数
#include <stdio.h>
int main()
{
int a, b, c, x, suma, sumb, sumc; //a百位,b十位,c个位
for (suma = 1, a = 1; a < 10; a++)
{
suma *= a;
for (sumb = 1, b = 0; b < 10; b++)
{
if (b > 0) sumb *= b;
for (sumc = 1, c = 0; c < 10; c++)
{
if (c > 0) sumc *= c;
x = 100 * a + 10 * b + c;
if (x == suma + sumb + sumc) printf("%d\n", x);
}
}
}
}
运行结果:
145
【项目3-反序数】
(1)输入一个正整数,输出它的反序数(反序数,即将其所有位的数字反过来。例如,123是321的反序数)
#include <stdio.h>
int main()
{
int n, m, k;
scanf_s("%d", &n);
m = 0;
k = n;
while (k > 0)
{
m = 10 * m + k % 10; //求末位数字,相加,乘10进位;
k = k / 10; //舍去末位数字,再循环;
}
printf("%d的反序数为%d", n, m);
}
(2)求1000000以内的正整数n,要求9n是n的反序数。
#include <stdio.h>
int main()
{
int n, m, k;
for (n = 1; n < 1000000; n++)
{
for (k = n, m = 0; k > 0; k /= 10) //求n的反序数m;
{
m = m * 10 + k % 10;
if (m==9 * n) printf("%d\t%d\n", n, m);
}
}
}
运行结果:
1089 9801
10989 98901
109989 989901
【项目4-回文数】
(1)输入一个正整数,判断其是否为一个回文数(例1221、12321都是回文数,正着看、倒着看,是同一个数).
#include <stdio.h>
int main()
{
int x, y, k;
scanf_s("%d", &x);
for (k = x, y = 0; k > 0; k /= 10)
{
y = y * 10 + k % 10;
}
if (x == y) printf("YES!\n");
else printf("N0!\n");
}
(2)输出10000以内的所有回文数。
#include <stdio.h>
int main()
{
int x, y, k,i=-1;
for (x = 1; x < 10000; x++)
{
for (k = x, y = 0; k > 0; k /= 10)
{
y = y * 10 + k % 10;
}
if (x == y)
{
i++;
if (i % 5 == 0)
{
printf("\n");
}
printf("%d\t", x);
}
}
}
【项目5-阿姆斯特朗数】
如果一个正整数等于其各个数字的立方和,则称该数为阿姆斯特朗数(亦称为自恋性数)。如 407=43+03+73就是一个阿姆斯特朗数。试编程求1000以内的所有阿姆斯特朗数。
解法一:
#include <stdio.h>
int main()
{
int x, a, b, c;
for (a = 0; a < 10; a++)
{
for (b = 0; b < 10; b++)
{
for (c = 0; c < 10; c++)
{
x = a * a * a + b * b * b + c * c * c;
if (x == 100 * a + 10 * b + c)
printf("%d\t", x);
}
}
}
}
运行结果:
153 370 371 407
解法2:
#include <stdio.h>
int main()
{
int i,m,k,n;
for(n=0; n<=1000; ++n)
{
//计算n的各位数的立方和m
k=n;
m=0;
while(k>0)
{
i=k%10;
m+=i*i*i;
k=k/10;
}
if(m==n) //n和其各位数的立方和相等
{
printf("%d\t", m);
}
}
printf("\n");
}
【项目6-回文日】
很有趣的一个题目:2011年11月02日是一个回文日:2011 1102,在2011级同学做这道题时我们刚刚度过这一天!请列出本世纪还有多少个回文日(假如我们能活到百岁,你和我的……)。注意:一年只有12个月
#include <stdio.h>
int main()
{
int year, month, day, y, ymd;
int is_cycle;
int count = 0;
for (year = 2015; year < 2100; year++)
{
y = year;//保留year数值,用y去做运算;
month = year % 100;//年份的后两位对应月;如:2015中取出15;
month = (month % 10) * 10 + month / 10;//把得到的月两位倒过来,15变51;
day = y / 100;//年份的前两位对应日,如2015中取出20;
day = day % 10 * 10 + day / 10;//将得到的日两位倒过来,20变02;
switch (month)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
if (day <= 31) is_cycle = 1;
break;
case 4:
case 6:
case 9:
case 11:
if (day <= 30) is_cycle = 1;
break;
case 2:
if (year % 4 == 0 && year % 100 == 0 || year % 400 == 0)
{
if (day <= 29)//闰年2月29天;
is_cycle = 1;
}
else
{
if (day <= 28)//非闰年2月28天;
is_cycle = 1;
}
break;
default:
continue;//如果你在switch中使用continue,continue生效是对于循环
//如果你在switch中使用break,break生效是对于switch。
}
if (is_cycle)
{
y = year;
ymd = year; //构造出年月日的形式供输出
while (y > 0) //应用倒序数的方法,合成年月日输出格式;
{
ymd = ymd * 10 + y % 10;
y = y / 10;
}
printf("%d\n", ymd);
count++;
}
}
printf("本世纪共有%d个回文日.\n", count);
printf("\n");
}