正整数分解使得乘积最大问题
参考文章:正整数分解使得乘积最大问题_小拳头的博客-CSDN博客_整数拆分乘积最大问题
一、问题描述
设n是一个正整数。现在要求将n分解为若干个自然数之和,使得自然数的成绩最大。输出这个最大的乘积。
要求:
(1)要求这些自然数互不相同
(2)要求这些自然数可以是相同的
二、问题分析:
对于第一问这类题一开始需要我们手写几个数来看看规律。先做第一问,要求自然数互不相同。从5开始写起,5=2+3,6=2+4,7=3+4,8=3+5,9=2+3+4,10=2+3+5,11=2+4+5
发现规律如下:
(1)尽量使得元素是连续的。
(2)如果有多出来的,从后往前均匀分配到各个元素。可能存在一个再某两个相邻数之间一个数比另一个大2的情况
下面举个栗子,看看携程实习生招聘笔试的这道题:
题目描述:乘积最大
有一个整数n,将n分解成若干个不同自然数之和,问如何分解能使这些数的乘积最大,输出这个乘积m。
输入:
一个整数,不超过50
输出
一个整数
样例输入
15
样例输出
144
c++代码实现:
#include<iostream> #include<vector> using namespace std; int main() { int n; cin >> n; vector<int> flag; int k = 2; while (n >= k) { flag.push_back(k); n = n - k; k++; } while (n) { for (int i = flag.size()-1; i >= 0; i--)//从大往小赋值,直到n=0;思考:如果数据偏大,有没有可能造成时间超时? { flag[i]++; n--; if (n <= 0) break; } } int result = 1; for (int i = 0; i < flag.size(); i++) { result *= flag[i]; } cout << result << endl; return 0; }
优化后:
#include<iostream> #include<vector> using namespace std; int main() { int n; cin >> n; vector<int> flag; int k = 2; while (n >= k) { flag.push_back(k); n = n - k; k++; } int add = n / flag.size();//计算每个都能加的最大数; n = n % flag.size();//取余运算,这部分值从大到小赋值,赋到n=0为止 int result = 1;//计算每个整数的乘积; for (int i = 0; i < flag.size(); i++) { flag[i] += add; } for (int i = flag.size() - 1; n > 0; i++) { flag[i]++; n--; } for (int i = 0; i < flag.size(); i++) { result *= flag[i]; } cout << result << endl; return 0; }
对于第二问,对于元素可以是相同的
仍然是通过手写几个数查看一下规律:4=2+2,5=2+3,6=3+3,7=3+2+2,8=3+3+2,9=3+3+3。
发现规律如下:
(1)元素不会超过4,因为4=2+2,又可以转化为2的问题,而5=2+3,5<2*3,所以5总能分解成2和3。
(2)尽可能多分解出3,然后分解出2,不要分出1。
考虑任意一个数,除以3之后的结果有以下3种:
(1)能被3除断,那么就分解为3+3+...+3的情况即可。例如9=3+3+3。
(2)被3除余1,分解为3+3+...+3+2+2或者3+3+...+3+4的情况,例如10=3+3+2+2
(3)被3除余2,分解为3+3+...+3+2的情况,例如11=3+3+3+2。
c++代码:
#include<iostream> #include<math.h> #include<vector> using namespace std; int main() { int n,result=1; cin >> n; vector<int> lst(n/3+1);//建立数组,存n分成的若干个数 int k1 = n / 3;//存整数部分 int k2 = n % 3;//余数 int m;//存进数组的数中有好多个3 if (k2 == 0) m = k1; else if (k2 == 1)//最后一个数为4 { lst[k1-1] = 4; m = k1-1 ; } else {//最后一个数为2 lst[k1] = 2; m = k1; } for (int i = 0; i < m; i++) { lst[i] = 3; } result= pow(3, m); /* 一定是“i<lst.size()”在前面,如果&&前面都不满足, 则不会进行&&运算后面部分 好处:防止超过vector数组lst的下界*/ for (int i = m;i<lst.size()&& lst[i] != 0; i++) result *= lst[i]; for (int i = 0; i < lst.size() && lst[i] != 0; i++) cout << lst[i]<<" "; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通