1005 继续(3n+1)猜想

1005 继续(3n+1)猜想 (25 分)

题目描述:

卡拉兹(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


解题思路:
题目要求一个列表中的关键数,而关键数的定义是 在列表中其他数字 “归一”的过程中产生的数字集合不包含其自身的数字。举个例子,[3, 6] ,3在 “归一”的过程中产生的中间数字有:“5,8,4,2,1”。而 6 并不包含在其中,所以6是一个关键数。而 3 不是,因为 6 “归一”的过程中产生了“3,5,8,4,2,1”,3是包含在其中的。
这样我们就需要在每个 可能是 关键数 的数字的“归一”过程中去否定那些不是关键数的其他数字。直到每个可能的关键数 都“归一”了,我们才能判断出哪些是关键数。


代码:

Python Version

def main():
    n = int(input())
    # 接收输入的整数,不过在本程序中并没有用到这个整数。
    data = [int(x) for x in input().split(" ")]
    # 接收将要判断的数字并存储为整数数组。
    # print(data)
    flag = [False for x in range(n)]
    # 用一个数组来表示 data中下标相同数字是否是 关键数
    for x in range(n):
        if flag[x]:
            # 这个数不是关键数
            continue
        else:
            temp = data[x]
            # 这个数还没有确定是否是关键数。也就是说,在前面所有数字 “归一” 的过程中还没有出现这个数字。
            while temp != 1:
            # 对这个数字“归一”
                if temp % 2 == 0:
                    temp //= 2
                else:
                    temp = (temp * 3 + 1) // 2
                if temp in data:
                    # 如果在“归一”过程中,出现了列表中的其他数字,说明其他数字不是关键数
                    # 列表的index方法可以返回列表中某一项第一次出现的下标。由于列表中的数字互不相同,所以这样做没有问题。
                    # 将不是关键字 对应的flag数据标志为 True
                    flag[data.index(temp)] = True
        # print(flag)
    res = []
    for x in range(n):
        if flag[x] == False:
        # 如果flag[x]是False,则对应的data[x]是关键数。
            res.append(data[x])
    res.sort(reverse=True)
    # 列表的sort方法可以对列表排序,默认为从小到大,设置reverse = True获得从大到小的排序结果
    res = [str(x) for x in res]
    # 将 res 从数字列表 转换为 字符列表
    print(" ".join(res))
    # 使用join函数拼接出答案并输出
    return


if __name__ == '__main__':
    main()

C++ Version

#include <iostream>
#include <algorithm>
#include <vector>
#define NN 100 + 10
using namespace std;

bool in(int temp, int* data, int K);

int main(){
	//freopen("in.txt", "r", stdin);
	int K = 0, temp;
	int data[NN];
	int flag[NN];
	for(int i=0; i<NN; ++i){
		flag[i] = 0;
	}
	cin >> K;
	for(int i=0; i<K; ++i){
		cin >> data[i];
	}
	for(int i=0; i<K; ++i){
		temp = data[i];
		while (temp != 1){
			if(temp % 2 == 0){
				temp /= 2;
			}else{
				temp = (temp * 3 + 1) / 2;
			}
			if(in(temp, data, K)){
				flag[temp] = -1;
			}
		}
	}
	vector<int> answer;
	for(int i=0; i<K; ++i){
		if(flag[data[i]] == 0){
			answer.push_back(data[i]);
		} 
	}
	sort(answer.begin(), answer.end());
	for(int i=answer.size()-1; i>0; --i){
		cout << answer[i] << " "; 
	}
	cout << answer[0] << endl;
	
	return 0;
}

bool in(int temp, int* data, int K){
	for(int i=0; i<K; ++i){
		if(temp == data[i]){
			return true;
		}
	}
	return false;
}
  • Java Version: 使用了“桶排序”的思想降序输出所有‘关键数’。
import java.util.Scanner;

public class Main{
	public static void main(String[] args) {
	
		Scanner in = new Scanner(System.in);
		int K = in.nextInt();
		// 接收输入的正整数K
		int[] inpus = new int[110];
		// 定义一个定长的整型数组,数组长度>100,java会自动把数组初始化为0.
		for(int i=0;i<K;++i) {
			inpus[i] = in.nextInt();
		}
		// 接收输入的K个正整数
		int[] flags = new int[110];
	    // 标记,flags[i] == -1 表示 inpus[i]不是一个"关键数";
		// flags[i] == 0表示inpus[i]是一个关键数
		int tmp = 0;
		for(int i=0;i<K;++i) {
			tmp = inpus[i];
			while(tmp != 1) {
				if(tmp % 2 == 0) {
					tmp = tmp / 2;
				}else {
					tmp = (tmp * 3 + 1) / 2;
				}
				for(int j=0;j<K;++j) {
					// 如果inpus[j]在tmp变1的过程中出现,就不是一个'关键数'
					if(inpus[j] == tmp) {
						flags[j] = -1;
					}
				}
			}
		}
		// 处理完毕,所有flags[i] == 0 对应的inpus[i]就是所有的"关键数"
		in.close();
		// 关闭输入流
		// 接下来就是将这些数字降序排序后输出。由于输入的K个不同的数字的大小都是
		// (1, 100], 我们可以运用"桶排序"的思想用一个标记数组,按降序遍历输出。
		int[] answer_flags = new int[110];
		// 稍大一点的标记数组
		int counter = 0;
		for(int i=0;i<K;++i) {
			if(flags[i] == 0) {
				counter ++;
				// 统计有多少个'关键字'
				answer_flags[inpus[i]] = 1;
				// 打上标记
			}
		}
		for(int i=100; i>1; --i) {
			// 降序输出
			if(answer_flags[i] == 1) {
				if(counter > 1) {
					System.out.print(i + " ");
				}else {
					System.out.print(i);
				}
				counter --;
				// 按格式输出,最后一个没有空格伴随。
			}
		}
	}
}

易错点:

  • 要搞清楚题目中关键数的定义

总结:
python_version

c++_version

java-success

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值