`
topman
  • 浏览: 15241 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

UVa 3n+1问题

阅读更多

UVa 3n+1 问题

<!---->1.       <!---->问题描述

编号 :100.

简单描述 : 就是对一个整数 ( 大于等于 1), 不断按照这样的规律进行运算 , 即如果当前数是偶数 , 则下一个数为当前数除以 2, 如果当前数为奇数 , 则下一个数为当前数乘 3 1, 整个过程直到计算到 1 为止 . 那么形成的数列的长度称为 cycle-length.

问题的输入是 : 给定一个区间 [a,b]

问题的输出为 : 输出给定区间 ( 含端点 ) 所以数的 cycle-length 的最大的 cycle-length.

详细描述可参见 这里 .

<!---->2.       <!---->问题分析

<!---->            <!---->2.1    直观分析

最直观的方法当然是采用蛮力法 ( brute-force), 将给定区间的每个数求出其 cycle-length, 然后在所以的 cycle-length 中找出最大的即可 .

<!---->            <!---->2.2    优化

优化是建立在分析的基础之上 .

我们先对一个简单例子进行实验 .

例如给定区间为 B[1,10], 1,2,3,4,5,6,7,8,9,10

通过简单分析我们可以知道 , 通常较大的数具有较大的 cycle-length, 所以我们可以首先取 A=9( 为什么不取 10, 是因为 9 在一次处理后可变为 28, 大于 10) 按照给定的规律来进行如下 :

9 28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1

可以看出 , 上面红色标记的部分 , 处于给定的区间内 , 而且它们的 cycle-length 显然是小于当前的数 9 cycle-length, 所以这些数可以从给定的区间内剔除掉 , 记住当前的 cycle-length, 于是

经过一次的操作后 , 给定的区间变为 3,6

继续按照这个方法进行 , 直至这个区间为空 , 停止 , 其中最大的 cycle-length 即为所求 .

<!---->            <!---->2.3    得出算法

算法的描述同 2.2 处优化部分的分析 , 具体的算法描述可见 3.

<!---->3.       <!---->算法描述

算法伪代码 ( C) 描述如下 :

function getMCL

B[left, right];  // 为给定的区间

mcl = 0;               //mcl max-cycle-length

while !B.empty()

{

A = getCandidate(B);// 这个函数是用来找出 B 区间内当前最适合处理的元素 ,

// 一般是最大的奇数 , 即预计可能具有较大 cycle-length 的元素

                     ccl = 1;          //ccl 是指 current-cycle-length

                     while (A!=1)

              {

                     ccl++;

                     A = (A%2)?(3*A+1):(A/2);

                     if find(B,A)           // 这个函数是用来判断 B 区间内是否存在中间结果 A

                            pop(B,A);       // 有则剔除

              }

              mcl = (mcl<ccl)?ccl:mcl;

       }

       return mcl;

 

<!---->4.       <!---->具体实现

#include "iostream"
using namespace std;

int getCandidate(int B[], int base, int n)
{
	int i;
	for (i = n-1; i>=0; i--)
	{
		if (((base+i) % 2)&&(B[i]==0))
			return i;
	}
	for (i = n-1; i>=0; i--)
	{
		if (!B[i])
			return i;
	}
	return -1;
}
int nadd2(int left, int right)
{
	int Blength = right - left + 1;
	int length = Blength;
	int *B = new int[length];
	for (int i=0; i<length; i++)
		B[i] = 0;
	int mcl = 0;
	while (length > 0)
	{
		int ccl = 1;
		int pos = getCandidate(B, left, Blength);
		if (pos==-1)
			break;
		B[pos] = 1;
		length--;
		int A = pos+left;
		while (A!=1)
		{
			ccl ++;
			A = (A%2)?(3*A+1):(A/2);
			int Apos;
			if ((A-left>Blength)||(B[A-left])||(A<left))
				Apos = -1;
			else
				Apos = A-left;
				
			//B[Apos] = 1;
			if (Apos!=-1)
			{
				B[Apos] = 1;
				length --;
			}
		}
		mcl = (mcl<ccl)?ccl:mcl;
	}
	delete[] B;
	return mcl;
}
int main()
{
	int left, right;
	while(cin>>left>>right)
		cout<<left<<" "<<right<<" "<<nadd2(left,right)<<endl;
	return 0;
}
 

 

<!----><!----><!---->

<!----><!----><!---->

<!---->5.       <!---->复杂性分析

主要的耗时部分是二层循环部分 , 而外层循环的次数主要取决于内层循环在区间内的命中率 . 没有进行过统计学的分析 , 但只要 candidate 选取合适 , 每次内层循环会有大于 50% 的命中率 .

假设区间内数 A 的内层循环次数 ( 即由 A 按照规则变为 1 cycle-length) X, 平均命中率为 p, 那么时间复杂度为 :

T(n) = X*T(n*(1-p))     // 其中 X 为平均的 cycle-length

<!---->6.       <!---->备注

在实现过程中 , 最初使用的是 C++ 中的 vector, 但运行时的实际耗时比使用数组的蛮力法还要长 , 经过分析 , 这是因为编译器在维护 vector 这个数据结构时所耗时长是比较大的 , 特别是当使用 vector earse 方法来删除某个特定元素时 . 所以最后还是使用最基本的数组来实现 , 用标记来指示删除状态 .

所以在实际的算法实现中 , 数据结构的选取也是非常重要的 , 所谓的程序 = 算法 + 数据结构是也 .

可以改进的地方包括有 :getCandidate 函数的算法 , 即如何预估一个具有较长 cycle-length 的元素 ; 还有当内层循环出现在区间内已标记为删除状态的元素中时 , 这时内层循环可终止 .

分享到:
评论
1 楼 leeldy 2009-02-03  
我用C写过这个东西,以前的做法就是如果这个数据范围在10w以内,直接开个数组count用来保存每个数的cycle-length,这样速度会快很多
如果只是运算一次的话,速度的提升不会很明显,但是如果有相当多的数据要计算的话,这种用空间换时间的速度是非常快的
具体做法如下:

初始化max=0;
开始输入:
得到一个区间,扫描这个区间内的每一个数,是否都已经计算过cycle-length,如果计算过,则直接取这个数于max比较
如果没有计算过就计算以后再取这个值(计算过程也可以利用以前计算过的数据来避免重复计算,开个临时数组当做堆栈)
一直到扫描完整个区间
此时就可以得出来max

因为以前计算过的所有数据都保存在数组count中,所以多次运算的话,已经计算过的数就不会再计算

说得有点笼统,但是这个问题是相当有技巧的
总是想方设法避免重复计算就可以了
但是如果数据很大的话,就需要仔细考虑一下细节问题了

相关推荐

    Uva 100(The 3n+1 problem) c 代码

    Uva 100 ,问题是The 3n+1 probelm ,可以ac的代码

    100 - The 3n + 1 problem.c

    UVA 100题答案

    UVA_示例代码

    这些数据结构在UVA题目中广泛运用,例如排序、搜索、图论问题等。 2. **算法**:包括排序算法(快速排序、归并排序、堆排序等)、搜索算法(深度优先搜索DFS、广度优先搜索BFS)、动态规划、贪心策略、回溯法、分治...

    uva 200~299 22道题解 均accept

    1. **uva201.cpp** - 这个可能是解决UVA第201号问题的代码。由于没有具体描述,我们假设这是一个关于数据结构、排序或搜索的经典算法问题。 2. **uva202.cpp** - 同样,这可能对应UVA的第202号问题,可能涉及字符串...

    uva最全ac代码

    【压缩包子文件的文件名称列表】"uva",虽然没有具体的文件名,但可以推测这些文件可能是按照UVA问题编号命名的,比如"100.cpp"、"259.py"等,代表了对应编号的UVA问题的解决方案。每个文件可能包含了特定问题的完整...

    Leetcode经典01背包-UVA_and_classic_problem:c++写的一些UVA题目的解答以及一些LeetCode的解答

    3n + 1 problem 151 - Power Crisis -&gt; 约瑟夫问题DP 问题 10607 - Joseph's Cousin -&gt; 约瑟夫问题变形 532 - Dungeon Master -&gt; BFS类型的题目 299 - Train Swapping 10038 - Jolly Jumpers 10193 - All You Need ...

    uva 50个题解

    通过解决UVA上的问题,程序员可以提升对复杂问题的分析能力,掌握如何高效地运用数据结构和算法来解决问题。同时,这些题解也适合作为面试准备的资料,因为许多企业在招聘时都会考察候选人的算法基础。 总的来说,...

    UVA题目大全

    UVA作为训练平台,为参赛者提供了大量的实际问题,涵盖数据结构、图论、数学、排序、搜索、动态规划等多个领域。 在【压缩包子文件的文件名称列表】中提到的"UVa代码",可能包含的是对UVA题目解题思路的注释代码,...

    python 3 中各种UVa(ACM)问题的解决方案_几乎所有_python_代码_下载

    在 Python 3 中解决了一些 UVA 问题

    Uva练习题

    UVA是一个广受欢迎的编程竞赛网站,它为程序员提供了一个展示编程技能和解决问题的平台。这里的“不是很难,试试吧”可能意味着这些题目适合初学者或者中等水平的程序员进行训练,旨在帮助提升算法理解和编程能力。 ...

    CPE:CPE:'(

    3n + 1问题 (CPE10400,UVA100) v 5, 你可以说11 (CPE10460,UVA10929) v 6, 孟加拉数字 (CPE10414,UVA10101) v 7 征服名单 (CPE21924,UVA10420) v 字元与字串 8。 什么是密码分析? ...

    uva 部分题目解决代码

    通过研究`test1`中的代码,我们可以看到具体是如何将这些理论知识应用于实际问题的,同时也能学习到代码的编写规范、调试技巧以及如何提高程序的运行效率。这对于提升编程能力和准备编程竞赛至关重要。 总之,"uva ...

    uvaoj 习题题目

    1. **算法基础**:UVa的题目中包含了各种基础算法,如排序(快速排序、归并排序、冒泡排序等)、搜索(深度优先搜索、广度优先搜索)、动态规划、贪心算法、回溯法等。掌握这些基本算法是解决大多数编程问题的基础。...

    UVa Online Judge部分题目代码

    1. **基础算法**:在UVa的题目中,你会看到基础算法的应用,如排序(冒泡、选择、插入、快速、归并排序等)、搜索(深度优先搜索DFS、广度优先搜索BFS)、动态规划、贪心策略等。这些算法是解决复杂问题的基础。 2....

    uva11859nim游戏 + 求素因子个数.cpp

    uva11859nim游戏 + 求素因子个数.cpp

    uva_base_hfut_v13.2.tar.gz

    1.Uva_base的编译 在编译球队时,则需要在当前球队文件夹下打开终端输入执行以下命令(以下命令都是在root下执行的): ./configure make clean make 如果运行Uva_base后,出现球员越界或掉线的情况,就重新...

    uva272 uva272 uva272

    uva272

    凸包 UVA109 题解

    UVA109的题解,经测试完全正确,还附有题解。

    uva531 LCS算法

    uva531最长公共子序列问题水题,应用简单的dp即可ac有更快速的方法欢迎讨论

    算法入门经典UVa配套题目pdf

    通过深入学习和实践《算法竞赛入门经典》UVa配套题目,你可以逐步掌握这些知识点,从而提升编程能力和算法素养,为参加各类编程竞赛或解决实际问题打下坚实基础。记得,理论知识结合实践是学习算法的关键,所以不仅...

Global site tag (gtag.js) - Google Analytics