题目:
点击:质数因子
本题我写了几种方法,由浅入深
看答案,让我们先分析一下题目,这个题目说的是给你一个数,让你用他的质因子表示出来,比如180=2 * 2 * 3 * 3 * 5
那么让我们先了解一个概念合数
合数是合数是指整数中除了能被1和本身整除外,还能被0除外的其他数整除的数
也就是说大于2的数不是质数就是合数
那么一个合数是不是就可以通过它的最小质因子乘以一个合数呢?
所以我们现在用大写字母表示合数,小写字母表示最小质因子,则A=a * B,那么这个B=A/a,
然后B=b * C,那么这个C=B/b,以此类推当,都是质因子的时候就拆解结束了
于是A=a * b * c * d…(任何一个合数都可以用一个素数与一个更小的合数的积表示,然后递归定义 )
根据这个原理可知一个合数的最小因子一定是它的最小质因子,因为它的因子(母体的因子)要么是质数要么是合数(不是母体),而合数还可以拆解成质数,因为这个合数(不是母体)是原本那个合数的因子(母体),而它拆解的质数是这个合数(不是母体)的因子,所以这个质数一定也是原来那个合数(母体)的因子,所以总的来说一个合数可以拆成很多因子,而这些因子一定是由它的质因子构成的,所以结论成立,这段文字不太说的明白,你记住就行,可以多看几遍!!
ps:母体就是最开始的合数A
看代码
int main()
{
int num, k, i = 0;
scanf("%d", &num);
for (k = 2; k <= num; k++)
{
while (num % k == 0)
{
printf("%d ", k);
num/=k;
}
}
return 0;
}
这里的num/=k其实就是求下一次的合数(B)
程序当num=1就结束了
由于一个合数的最小因子一定是它的最小质因子
所以这个num % k == 0是行的通的,这个k就是最小因子,那么也就是最小质因子喽
就这样循环
其实一开始我也没想到,一开始的代码我给你们看看(老脸豁出去啦)
#include<stdio.h>
int isprime(int i)
{
int count = 0;
for (int j = 1; j <= i; j++)
{
if (i % j == 0)
count++;
}
if (count == 2)
return i;
else
return 0;
}
int main()
{
long num = 0;
scanf("%d", &num);
while (num != 1)
{
for (int k = 1; k <= num; k++)
{
if (num % k == 0)
{
if (isprime(k))
{
printf("%d ", k);
num /= k;
break;
}
}
}
}
return 0;
}
现在看来,那个判断素数的步骤是不是多此一举啦!
但是我们发现改过的代码数据还是不能都过
代码其实没有错,就是运行时间超了,那我们一个优化一下!!
我们得知道一个合数的最小质因子不会超过它的开根号+1的
我们证明一下:
一个合数如果有超过两个因子的话
我们假设这个合数为n,因子为p[i],最小因子(最小质因子,上面提到过)为p
那么n=p[1]*p[2]p[3]…
那么p<=p[2],这个能理解吧,我们这里说的所有因子都是从小到大哦
于是根据不等式pp<=p[1]*p[2]<=p[1]*p[2]*p[3]…=n
那么p<=sqrt(n)
这不就证明出来了嘛
看优化后的代码:
int main()
{
int num, k, i = 0;
scanf("%d", &num);
for (k = 2; k <= num; k++)
{
//最小质数因子必小于输入数字的平方根
if (k > sqrt(num) + 1)
{
k= num;
}
while (num % k == 0)
{
printf("%d ", k);
num/=k;
}
}
return 0;
}
这优化了遍历的次数
我们的中心思想是什么??我们要获取最小质因子k啊,当我们找到了所有的质因子后,我们就不需要在循环了呀,那我们该怎么操作?、
于是就优化了!!
k在不停的加,而num在不停的减小,他们之间有着一层关系就是 (k<=sqrt(num)) 一旦打破这层关系,我们就不需要循环了,不优化前他就还在循环!!
可能博主说的有点麻烦,但是只要读者能看懂,那我就心满意足啦!!
这个合数的思想也用于欧拉筛法哦