1.问题描述
设 为一自然数, 可分解成若干个不同的自然数的和。这样的分法有很多种:比如 , 可按照下述方式分解:
编 号 | 分解方式举例 |
---|---|
1. | 10=5+4+1; |
2. | 10=3+2+3+2; |
3. | 10=7+3; |
4. | 10=6+4; |
5. | 10=7+2+1; |
6. | 10=6+3+1; |
7. | …… |
在所有这些分法中,各加数乘积最大的为36, (10=3+3+2+2中加数的乘积为3*2*3*2=36)。
试编写程序,求各种分解方法中各加数乘积的最大值。
1.1 程序输入输出描述
输入要求:输入只有1行,自然数 。
输出要求:输出也只有1行,所有分解方法中各加数乘积的最大值。
2 清奇思路以及其证明(需要允许加数相同)
因为网页版没找到作者的名字,所以没有贴,如果有同学知道的,我把出处贴完整。
链接:https://www.zhihu.com/question/30071017/answer/47584748
来源:知乎
著作权归作者所有。
把一个正整数N拆成若干正整数只有有限种拆法,所以存在最大乘积。
假设
并且
是最大乘积。
结论:
1. 乘积中不存在1或者超过(包含)5的整数。
2. 选用尽量多的3,直到剩下2或者4时用2;
证明:
1. 显然1不会出现在其中;
2. 如果存在
,则我们将
改为
。而
。所以不存在大于等于5的因子;
3. 4=2+2,乘积不变,不妨设没有因子4;
4. 如果有三个以上的2, 那么
,所以替换成3乘积更大
对于2.证明,可能一开始看不懂,这里详细再说一下:
因为
,所以
,所以
,所以
。
自己写的简单代码实现:
#include <iostream>
using namespace std;
int pow(int base,int exponent)
{
//简单实现
int j=1;
for (int i = 0;i<exponent;++i)
j*=base;
return j;
}
int main() {
int N=0,factor2=0,factor3=0;
int multiplication_Max=0;
cin>>N;
if(N <= 3)
cout<<N;
else
{
int reminder = N % 3;
switch(reminder)
{
case 0: factor3 = N/3;break;
case 1:
{
factor3 = N/3-1;
factor2 = 2;
break;
}
case 2:
{
factor3 = N/3;
factor2 = 1;
break;
}
}
multiplication_Max = pow(3,factor3)*pow(2,factor2);
cout<<multiplication_Max<<endl;
}
return 0;
}
如果至少要分成两个数之和,那么上述代码在开头需要微调:
if(N <= 3) ====> if(N <= 3)
cout<<N; ====> cout<<N-1;
3.常规:动态规划的思路
原博客链接:
https://blog.csdn.net/FD1247/article/details/70146062
根据题意,对于一个整数n,必然存在一个整数x,使得从n中分解出整数x可以使其最后获得最大乘积,这要求对n-x的分解也是最优解。我们用dp[i][j]表示从整数i分解出整数j的这种情况下,能达到的最大乘积。那么dp[i][j]可以递归的定义为
4.不允许加数相同的情况
详细参见:https://blog.csdn.net/xiaoquantouer/article/details/70142739
看完上面的之后,再看这个大神的作品(第三题)会代码上好懂一些:https://blog.csdn.net/flushhip/article/details/79751082
(不过这个本意是用来求允许加数相同的,但是只要稍稍改一下就好)