正整数分解使得乘积最大问题

参考文章:正整数分解使得乘积最大问题_小拳头的博客-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;
}

 

  

posted @ 2022-02-16 23:34  Grit_L。  阅读(667)  评论(0编辑  收藏  举报