这就是清华大学大一上对学生的严格要求。
这道题难点是首要掌握什么是质因数,以及质因数的性质。
考察知识点:
文件读写,质因数性质,循环,逻辑
质因数(素因数或质因子)在数论里是指能整除给定正整数的质数,质因数的一个重要性质是:任何正整数皆有独一无二的质因子分解式
这里第一种方法,我在不知道这一个重要性质的前提下,遍历了一个数所有的质因数可能性。导致使用了4层循环
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
#include<math.h>
//2018年2月23日10:50:58——February 23, 2018 10 : 50 : 58
//追梦少年 QQ:1131052403 —— Dreamer QQ : 1131052403
//开源的狂热爱好者,代码风骚,效率恐怖 —— Open source enthusiasts, code coquettish, efficient horror
//判断是否为素素
_Bool isSUSU(int n)
{
if (n == 1)
{
return 1;
}
for (int i = 2; i <= sqrt(n); i++)
{
if (n % i == 0)
{
return 0;
}
}
return 1;
}
//获取第n个数,其所有质因数比k小。
int getIt(int k,int n)
{
//不能为负数
if (k < 0 || n < 0)
{
return 0;
}
else
{
int count = 1;//初始化个数为1,代表特殊的1
int current = 2; //当前数字变为比1大一位的数
while (count < n && current < INT_MAX)//如果个数小于n,当前个数小于int最大值,循环
{
if (current < k && isSUSU(current))//如果当前的数比k小,并且是素素,这让个数加1,当前个数加1
{
count++;
current++;
continue;
}
int flag = 0;//代表当前数字是否有效
int i = 2; //当i大于sqrt(current),不用再判断。
int temp = current;//备份
int kkk = 2;//当前数从kkk开始除,当前数从kkk除到sqrt(current)
/*遍历当前current所有的质因数乘积的组合*/
while (kkk<=sqrt(current))
{
temp = current;
i = kkk++;
/*核心:下面的for +while循环 是计算当前current的某一个质因数乘积的组合*/
for (; i <=temp && i <= sqrt(current); i++)
{
if (!isSUSU(i))
{
continue;
}
while (temp %i == 0)//能整除i
{
flag=1; //如果没有能整除的数,则flag = 0
temp = temp / i; //循环除以
if ( isSUSU(temp))
{
if (temp >= k)
{
flag =0;
}
break;
}
}
}
if (!flag)
{
break;
}
}
if (flag)
{
count++;
}
current++;
}
if (count == n)
{
return --current;
}
else
{
return 0;
}
}
}
void main()
{
//打开文件
FILE * pf = fopen("C:\\Users\\A\\source\\repos\\清华大一试题\\清华大一试题\\data.txt", "r");
if (pf == NULL)
{
return;
}
// 第一行赋值给k,第二行赋值给n
char str[10] = { 0 };
fgets(str, 9, pf);
int k = atoi(str);
memset(str, 0, 10);
fgets(str, 9, pf);
int n = atoi(str);
fclose(pf);
//获取
int p = getIt(k,n);
//打印
printf("%d", p);
system("pause");
}
方式二:知道任何正整数皆有独一无二的质因子分解式
证明:
非空正整数集里存在最小的元素”,一定有一个最小的数M,它能用至少两种方法表示成质数的乘积:
M = P1 * P2 * … * Pr = Q1 * Q2 * … * Qs
下面我们将看到,这种假设会推出一个多么荒谬的结果来。不妨设P1 <= P2 <= … <= Pr, Q1 <= Q2 <= … <= Qs。显然,P1是不等于Q1的,不然两边同时约掉它,我们就得到一个更小的有两种分解方法的数。不妨设P1 < Q1,那么我们用P1替换掉等式最右边中的Q1,得到一个比M更小的数T = P1 * Q2 * Q3 * … * Qs。令M’ = M – T,我们得到M’的两种表达:
M’ = (P1 * P2 * … * Pr) – (P1 * Q2 * … * Qs) = P1 * (P2 * .. * Pr – Q2 * … * Qs) …… (1)
M’ = (Q1 * Q2 * … * Qs) – (P1 * Q2 * … * Qs) = (Q1 – P1) * Q2 * … * Qs ……………… (2)
由于T比M小,因此M’是正整数。从(1)式中我们立即看到,P1是M’的一个质因子。注意到M’比M小,因此它的质因数分解方式应该是唯一的,可知P1也应该出现在表达式(2)中。既然P1比所有的Q都要小,因此它不可能恰好是(2)式中的某个Q,于是只可能被包含在因子(Q1-P1)里。但这就意味着,(Q1-P1)/P1除得尽,也就是说Q1/P1-1是一个整数,这样Q1/P1也必须得是整数。我们立即看出,P1必须也是Q1的一个因子,这与Q1是质数矛盾了。这说明,我们最初的假设是错误的。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
#include<math.h>
//2018年2月23日10:50:58——February 23, 2018 10 : 50 : 58
//追梦少年 QQ:1131052403 —— Dreamer QQ : 1131052403
//开源的狂热爱好者,代码风骚,效率恐怖 —— Open source enthusiasts, code coquettish, efficient horror
//判断是否为素素
_Bool isSUSU(int n)
{
if (n == 1)
{
return 1;
}
for (int i = 2; i <= sqrt(n); i++)
{
if (n % i == 0)
{
return 0;
}
}
return 1;
}
//获取第n个数,其所有质因数比k小。
int getIt2(int k, int n)
{
//不能为负数
if (k < 0 || n < 0)
{
return 0;
}
else
{
int count = 1;//初始化个数为1,代表特殊的1
int current = 2; //当前数字变为比1大一位的数
while (count < n && current < INT_MAX)//如果个数小于n,当前个数小于int最大值,循环
{
if (current < k && isSUSU(current))//如果当前的数比k小,并且是素素,这让个数加1,当前个数加1
{
count++;
current++;
continue;
}
int flag = 0;//代表当前数字是否有效
int i = 2; //当i大于sqrt(current),不用再判断。
int temp = current;//备份
/*核心:下面的for +while循环 是计算当前current的唯一个质因数乘积的组合*/
for (; i <= temp && i <= sqrt(current); i++)
{
if (!isSUSU(i))
{
continue;
}
while (temp %i == 0)//能整除i
{
temp = temp / i; //循环除以
if (temp < k&& temp!=1&& isSUSU(temp) )
{
flag = 1;
}
}
}
if (flag)
{
printf("%d", current);
count++;
}
current++;
}
if (count == n)
{
return --current;
}
else
{
return 0;
}
}
}
void main()
{
//打开文件
FILE * pf = fopen("C:\\Users\\A\\source\\repos\\清华大一试题\\清华大一试题\\data.txt", "r");
if (pf == NULL)
{
return;
}
// 第一行赋值给k,第二行赋值给n
char str[10] = { 0 };
fgets(str, 9, pf);
int k = atoi(str);
memset(str, 0, 10);
fgets(str, 9, pf);
int n = atoi(str);
fclose(pf);
//获取
int p = getIt(k,n);
//打印
printf("%d", p);
system("pause");
}
灾难总是接踵而至,如果我失败了,只能说明我不过是如此程度的男人。