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

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

时间限制
400 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
CHEN, Yue

卡拉兹(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
 
 
以上是原题,以下是分析:
①分析3n+1的基本算法:
f(n)=n/2 (n为偶数)
	(3*n+1)/2 (n为奇数)

②所谓覆盖,就是指3->5->8->4->2->1
以上从左往右是覆盖关系,如3覆盖5
所以,只需保存两数之间的覆盖数3。

③接着分析一下题目输入、输出:
3 5 6 7 8 11
显然6->3->5->8 7->11,所以3 5 8 11不作考虑,而输出6 7

④下面是算法问题(我的算法,可能不是最好的):
	1,用一个数组保存所有数
	2,从左往右n[i]判断是否与n[0~n-1]是覆盖关系
		如果是,被覆盖数置0;否则继续。
		//这里覆盖关系是有先后顺序之分的
	3,排序
	4,打印结果(反复置0之后,最终不为0的就是关键数)

下面是伪代码
boolean check(int a, int b)
{
	//b做3n+1运算,直至a==b或b==1
	return a==b;
}
void main()
{
	//1,输入K,输入K个整数,并用数组保存
	//2,调用check方法,判断是否为覆盖关系,如果是,被覆盖数置0;否则继续
	for(int i=0 ; i<K ; i++)
	{
		for(int j=i+1 ; j<K ; j++) 
		{
			if(check(n[i], n[j])) n[i]=0;		//n[i]数被覆盖
			else if(check(n[j], n[i])) n[j]=0;		//n[j]数被覆盖
		}
	}
	//3,排序
	//4,打印结果
}

//Java

package package1;

import java.util.Arrays;
import java.util.Scanner;

public class PAT1005 {

	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);

		int K = scan.nextInt();
		int[] n = new int[K];
		for (int i = 0; i < K; i++) n[i] = scan.nextInt();

		// Work
		int count = 0;
		for (int i = 0; i < K; i++) {
			for (int j = i + 1; j < K; j++) {
				if (n[i] * n[j] == 0) continue;
				if (check(n[i], n[j])) {
					n[i] = 0;
					count++;
				} else if (check(n[j], n[i])) {
					n[j] = 0;
					count++;
				}
			}
		}

		Arrays.sort(n);
		for (int i = K - 1; i >= count + 1; i--)
			System.out.print(n[i] + " ");
		System.out.print(n[count]);
	}

	// a: Being checked, b: Checker
	public static boolean check(int a, int b) {
		while (a != 1 && b != 1 && a != b) {
			b = (b % 2 == 0 ? b / 2 : (3 * b + 1) / 2);
		}
		return a == b;
	}
}


//C语言
<span style="font-family:Microsoft YaHei;font-size:24px;">#include<stdio.h>

int check(int, int);
void bubble_sort(int[], int);

int main()
{
	int K, i, j;
	scanf("%d", &K);
	int n[K];
	for (i = 0; i < K; i++) scanf("%d", &n[i]);

	// Work
	int count = 0;
	for (i = 0; i < K; i++)
		for (j = i + 1; j < K; j++)
		{
			if (n[i] * n[j] == 0) continue;
			if (check(n[i], n[j]))
			{
				n[i] = 0;
				count++;
			}
			else if (check(n[j], n[i]))
			{
				n[j] = 0;
				count++;
			}
		}

	//Sort
	bubble_sort(n, K);

	for (i = K - 1; i >= count + 1; i--) printf("%d ", n[i]);
	printf("%d", n[count]);
	
	return 0;
}

// a: Being checked, b: Checker
int check(int a, int b)
{
	while (a != 1 && b != 1 && a != b)
		b = (b % 2 == 0 ? b / 2 : (3 * b + 1) / 2);
	return a == b;
}

void bubble_sort(int a[], int len)
{
	int i, j, temp;
	for(i=0 ; i<len ; i++)
		for(j=i+1 ; j<len ; j++)
			if(a[i]>a[j])
			{
				temp = a[i];
				a[i] = a[j];
				a[j] = temp;
			}
}</span>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值