/*
* 设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;
}
最优分解问题
最新推荐文章于 2022-08-12 17:20:41 发布