Dynamic Programming 计算第N个guly数

             求正整数中第n个guly数,guly数是因式分解后,所有的因子最终必须是2、3或5的倍数。仅通过数学方法计算判断一个数是否是guly数,比较简单,但是为什么第n个guly数的求解是采用了dynamic programming思想呢?

             Dynamic Programming下文简称DP,其思想的核心和问题的分辨是:后面的解答是前面解答的累加或累乘。

            既然如此:我们再来看一看问题,guly序列当中,任意一个guly数必须是2||3||5的倍数,只不过是2,3,5其中一个或几个的第几倍而已,那么我们可以想一下,后面的一个数一定是前面某个guly的(2,3,5)倍数,为什么呢?因为所有的数都是2||3||5的倍数,但是这样思考好像又不对,因为2*7=14不是guly。

            但是当后面的数是前面某个guly的倍数,而前面某个guly也是再前面某个guly的倍数,类推:再前面某个guly数一定是2、3或者5的倍数,则后面的数也必然是2,3,5的倍数(因为把所有前面guly的倍数一除,则剩下了再前面某个guly)。

            至于第i个guly数是前面哪个guly的倍数,依据的原理是2,3,5当前顺序序号倍数的最小值,即我们依次让3个下标分别指向3个guly,但这3个下标a,b,c必须毫不动摇的分别指向2,3,5的倍数的guly数,我们再计算下一个guly时,将a,b,c所指的当前guly分别乘以2,3,5,得到3个guly数,则这3个数中的最小一个即是第i个guly数,然后将最小一个所对应的a,b,c下标增1,以指向2的下一个guly数(如果a==2),(注:这里讲解不够清晰,需深入理解guly数的依次排列规则)这样就保证了后面得到的guly就一定是前面guly的倍数即2,3,5的倍数,而且依次一个不漏地求出了顺序增大的guly数。

          其DP思想是:后面的guly数依据前面已计算出的guly得出,不需要重复计算,利用了已计算得到的结果,并对前面guly数进行累乘来得到,所以提高了计算效率,这就是DP的本质。下面是实现的代码:

int DynamicProgramming::gulyDynamic(int n)
{
	std::vector<int>guly;
	guly.push_back(1);                                             //我们初始化第一个guly数为1
	                                                              //该方法的原理是:后面的数是前面的数的2||3||5倍
	                                                              //所以可以利用dynamic方法:后面的数建立在前面的数的基础之上,即倍数或和
	int result2, result3, result5;
	std::vector<int>result;
	int index2, index3,index5;//后面的数要么是2的倍数、3的倍数或者5的倍数,而这3者中最小的一个则是后面逐渐增加的一个
	index2 =index3 =index5 = 0;
	while (n>1)
	{
		result2 = guly[index2] * 2;
		result3 = guly[index3] * 3;
		result5 = guly[index5] * 5;                                     //方法类似于归并排序中的conquer
		result = conquerMin(result2, result3, result5);

		for (int i = 0; i < result.size();i++)
		{
			if (i==0)
			{
				guly.push_back(result[i]);                  //返回最小的结果
				n--;
			}
			else
			{
				switch (result[i])
				{
				case 2: index2++; break;
				case 3:index3++; break;
				default:index5++; break;
				}
			}
		}//for(i)

		if (n <= 1)
		{
			break;
		}
	}//while

	return guly[guly.size() - 1];                          //返回最后一个数即第n个guly
}

        由于2,3,5的倍数中取最小的一个,所以采用了归并算法如下:

std::vector<int> DynamicProgramming::conquerMin(int num2, int num3, int num5)
{
	std::vector<int>result;
	
	std::vector<Point>num;
	Point p2 = *new Point();
	p2.setData(num2);
	p2.setX(2);     
	num.push_back(p2);

	Point p3 = *new Point();
	p3.setData(num3);
	p3.setX(3);
	num.push_back(p3);

	Point p5 = *new Point();
	p5.setData(num5);
	p5.setX(5);
	num.push_back(p5);
     
	//---------------------归并排序调用函数------------------------
	mergeSort(num, 0, num.size() - 1);

	int minNum = num[0].getData();                                 
	result.push_back(minNum);
	for (int i = 0; i < num.size();i++)
	{
		if (num[i].getData()==minNum)
		{
			int index = num[i].getX();
			result.push_back(index);
		}
	}

	return result;                               //一个返回值包含2个不同意义的返回值
}

void DynamicProgramming::mergeSort(std::vector<Point>&num, int low, int high)
{
	if (low<high)
	{
		int mid = (low + high) / 2;
		mergeSort(num, low, mid);
		mergeSort(num, mid + 1, high);
		conquer(num, low, mid, high);
	}
}

void DynamicProgramming::conquer(std::vector<Point>&num, int low, int mid, int high)
{
	int i = low;
	int j = mid + 1;
	std::vector<Point>result;
	while (i<=mid&&j<=high)
	{
		if (num[i].getData()<num[j].getData())
		{
			result.push_back(num[i]);
			i++;
		}
		else
		{
			result.push_back(num[j]);
			j++;
		}
	}

	while (i<=mid)
	{
		result.push_back(num[i]);
		i++;
	}

	while (j <= high)
	{
		result.push_back(num[j]);
		j++;
	}


	for (int i = 0,k=low; i < result.size()&&k<=high;i++,k++)
	{
		num[k] = result[i];
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值