PAT 1005 解析


一、题目详情


问题描述:继续(3n+1)猜想

卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂。

当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对 n=3 进行验证的时候,我们需要计算 3、5、8、4、2、1,则当我们对 n=5、8、4、2 进行验证的时候,就可以直接判定卡拉兹猜想的真伪,而不需要重复计算,因为这 4 个数已经在验证3的时候遇到过了,我们称 5、8、4、2 是被 3“覆盖”的数。我们称一个数列中的某个数 n 为“关键数”,如果 n 不能被数列中的其他数字所覆盖。

现在给定一系列待验证的数字,我们只需要验证其中的几个关键数,就可以不必再重复验证余下的数字。你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。

输入格式:

每个测试输入包含 1 个测试用例,第 1 行给出一个正整数 K (<100),第 2 行给出 K 个互不相同的待验证的正整数 n (1<n≤100)的值,数字间用空格隔开。

输出格式:

每个测试用例的输出占一行,按从大到小的顺序输出关键数字。数字间用 1 个空格隔开,但一行中最后一个数字后没有空格。

输入样例:

6
3 5 6 7 8 11

输出样例:

7 6

代码长度限制:16 KB

时间限制:400 ms

内存限制:64 MB


二、题目解析


代码:

#include <stdio.h>
#include <stdlib.h>
#define SIZE 100

int main()
{
	/*
	* num:正整数(输入数据)的个数
	* input:指向动态开辟内存空间,用于存储正整数(输入数据)
	* tempArr[SIZE]:用于存储中间数,初始化为0
	* temp:数组排序时所需的临时变量
	* value:用于存储给一个正整数(输入数据)
	* first:标记数组tempArr的第一个元素,1为是,0为否
	* flag:标识关键数,1为是,0为否
	* i,j,k:循环变量
	*/
	int num = 0;
	int i, j, k;
	int tempArr[SIZE]={0}, temp, value;
	int flag, first;
	int* input = (int *)malloc(sizeof(int) * num);
	//获取输入正整数(输入数据)的个数
	scanf("%d", &num);
	//获取正整数(输入数据)
	for(i=0;i<num;i++)
		scanf("%d", &input[i]);
	//从大到小排序,便于结果按从大到小输出
	for(i=0;i<num-1;i++)
	{
		for(j=i+1;j<num;j++)
		{
			if(input[i]<input[j])
			{
				temp = input[i];
				input[i] = input[j];
				input[j] = temp;
			}
		}
	}
	//针对每个整数(输入数据),将递推中产生的每个数,不重复且从小到大存储在数组tempArr中
	flag = 1;//标识数组tempArr的第一个元素
	for(i=0;i<num;i++)
	{
		value = input[i];
		while(value != 1)//递推直至value为1
		{
			value = (value % 2 == 0) ? value / 2 : (value * 3 + 1)/2;
			for(j=0;tempArr[j]!=0;j++)
			{
				if(flag == 1)//表示数组tempArr的第一个元素未赋值
				{
					tempArr[i] = value;//将value存储在数组tempArr的第一位
					flag = 0;//数组tempArr的第一个元素已赋值
					break;
				}
				if(tempArr[j] == value)//数组tempArr中已存在value
					break;
				if(tempArr[j] > value)//将value按照从小到大插入数组tempArr中
				{
					for(k=SIZE-1;k>j;k--)
						tempArr[k] = tempArr[k-1];
					tempArr[j] = value;
					break;
				}
			}
			if(j<SIZE)//将value存在在数组tempArr的最后一位
				tempArr[j] = value;
		}
	}
	//确认关键数并从大到小输出
	first = 1;//标识输出第一个关键数
	for(i=0;i<num;i++)
	{
		flag = 1;//标识关键数
		for(j=0;tempArr[j]!=0;j++)
		{
			if(input[i] == tempArr[j])//整数(输入数据)出现在数组tempArr中
			{
				flag = 0;//不是关键数
				break;
			}
		}
		if(flag == 1)//是关键数
		{
			if(first == 1)//输出第一个关键数
			{
				printf("%d", input[i]);//不带空格
				first = 0;//已输出第一个关键数
			}
			else//输出其他关键数
				printf(" %d", input[i]);//带空格
		}
	}
    return 0;
}

提交结果(分数/满分):

22/25

测试点4:段错误 

表明:您的程序发生段错误,可能是数组越界,堆栈溢出(比如,递归调用层数太多)等情况引起。原因不详,高手指点,拜谢!

提示:

1. 数组排序问题

1)根据题目要求,从大到小输出关键数,故可先将数组input进行从大到小排序

本输入样例的排序结果为:

11 8 7 6 5 3

2)将递推过程中产生的一系列整数,按照从小到大的顺序依次存储在数组tempArr中

本输入样例产生的一系列整数为:

1 2 3 4 5 8 10 11 13 17 20 26

2. 关键数确定方法

数组input中的元素值不应出现在数组tempArr中,否则记为非关键数,故输出结果为:

7 6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值