最优分解问题

/*
* 设n是一个正整数。现在要求将n分解为若干个互不相同的自然数的和,
* 且使这些自然数的乘积最大。
* 
* 看到这个问题,不由得想到小学的一道题,将一根长n的木条拆成四份,使得这四根木条可以拼成
* 长方形,并问怎样拆分使得面积最大。
* 很自然的想到,每根n/4,拼成正方形面积最大。
* 证明:假设正方形边长为a,则s1=a^2。现在相对的两条边分别增加和减少b,
*		则s2=(a-b)(a+b)=a^2-b^2<s1。
* 随着b越大,s2会越小。
* 因此在分解数的时候注意分解后相邻的两个数的差绝对值要尽可能小。
* 
* n是奇数,设n=2*k-1。k>=1。
* 因此n可以拆成连续的两个自然数k-1和k。
* (k-1)*k-n=k^2-3*k+1,k=1和2时,n=1和3,(k-1)*k<n,不可以拆分;k>=3,即n>=5时,可以拆分。
* n是偶数,设n=2*k,k>=1。
* 则n拆成k-1和k+1。(k-1)(k+1)-2*k=(k-1)^2-2,k=1和2时,n=2和4,(k-1)(k+1)<2*k,不可以拆分。k>=2,n>=6,可以拆分。
* 因此当n<5时是不需要进行分解的。
* 
* n>=5时,应该依次从2、3、4......进行分解,刚好分解完是我们最想看到的结果。但是如果还剩下一个数不好继续分解了,
* 这个数就会与前面的某个数重复,根据分解后相邻的两个数的差绝对值要尽可能小。我们可以把这个数拆成若干个1,
* 从后往前,依次分给之前的分解好的数字(其他分配方案一定会导致重复元素出现)。便是最终结果。
*/
#include<iostream>
using namespace std;
void dicomp(int* f,int num, int last=2);//num是剩余未分配数字之和,当前应该分配的数字
int main()
{
	int num;
	cin >> num;
	int* f = new int[num + 1];
	memset(f, 0, sizeof(f));
	int result=1;
	dicomp(f, num);
	for (int i = 1; i <= num; i++)
		if (f[i] == 1)
			result *= i;
	cout << result<<endl;
	delete[] f;
	return 0;
}

void dicomp(int* f,int num, int last)
{
	if (num < 5&&last==2)//刚一传进来的数就比5小
		f[num]=1;
	else
	{
		if (num >= last)//可以继续分配
		{
			f[last] = 1;
			dicomp(f, num - last, last + 1);
		}
		else//不能继续分配了
		{
			if (num == 0)//刚好分配完
				return;
			f[last] = 1;
			f[last - num] = 0;
		}
	}
	return;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值