//1005 继续(3n+1)猜想 (25)(25 分)
//卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂。
//
//对任何一个自然数n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把(3n+1)砍掉一半。这样一直反复砍下去,最后一定在某一步得到n=1。卡拉兹在1950年的世界数学家大会上公布了这个猜想,传说当时耶鲁大学师生齐动员,拼命想证明这个貌似很傻很天真的命题,结果闹得学生们无心学业,一心只证(3n+1),以至于有人说这是一个阴谋,卡拉兹是在蓄意延缓美国数学界教学与科研的进展
//当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对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
C:
#include
int main(int argc, const char * argv[]) {
int K = 0,n =0;//K作为数字的数量,且用于控制输出' '或'\n'
int number[101] = {0};//为了防止越界等情况多设置一位,分为0-100块
scanf("%d",&K);//输入K
for (int i = 0; i < K; i++) {//因为数字在1-100之间,所以把有数字的块置1,后续处理flag是1的块即可
scanf("%d",&n);
number[n] =1;
}
for (int j = 1; j <= 100; j++) {
if (number[j]) {//处理flag=1的块
for (n = j;n > 1; ) {//这里需要有n>1,否则死循环
if (n % 2) {
n = (3*n+1)/2;
}else n = n/2;
if ( n <= 100 && number[n] ) {//这里需要注意不加<=100的话,当*3以后大于100后把number[100+]置0,会越界\
//为什么这里必须n<=100放在前面?如果number[n]放前面的话会段错误\
// 在XCODE下没问题,PTA平台段错误,测试点3、4\
//猜测:如果number[n]在前面的话,从左往右读,当如n=99的数进来,处理完n>100,判断number[100+]==1时越界\
// 而n<=100在前面的话,从左往右读,此时已经跳出if判断了
number[n] =0;
K--;
if(n < j) break;
}
}
}
}
for (int l = 100; l >= 1; l--) {
if (number[l] == 1) {
printf("%d%c",l,--K ? ' ' : '\0');
}
}
return 0;
}
1.越界问题
2.死循环问题
3.n<=100 && number[n]先后问题
先n<=100不越界
先number[n]会越界,当n=100+时越界
网友评论