清华大学大一上C语言机试第一题:K阶好数

这就是清华大学大一上对学生的严格要求。

这道题难点是首要掌握什么是质因数,以及质因数的性质。

考察知识点:

文件读写,质因数性质,循环,逻辑

质因数(素因数或质因子)在数论里是指能整除给定正整数的质数,质因数的一个重要性质是:任何正整数皆有独一无二的质因子分解式

这里第一种方法,我在不知道这一个重要性质的前提下,遍历了一个数所有的质因数可能性。导致使用了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");
}


灾难总是接踵而至,如果我失败了,只能说明我不过是如此程度的男人。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值