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

一、问题描述

设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)如果有多出来的,从后往前均匀分配到各个元素。考虑到一种特殊情况,当多出来的数比前面已有元素的个数大1时(比如8的情况),先给已有元素的最大元素加1,然后再均匀分配到每个元素。

 

下面举个栗子,看看携程实习生招聘笔试的这道题:

题目描述:乘积最大

有一个整数n,将n分解成若干个不同自然数之和,问如何分解能使这些数的乘积最大,输出这个乘积m。

输入:

一个整数,不超过50

输出

一个整数

样例输入

15

样例输出

144

 

c++代码实现:

#include<iostream>
#include<vector>
using namespacestd;
 
int main(){
    int num;
    while(cin>>num){
        int flag[100] = {0};
        int k=2;
        int i=0;
        while(num >= k){
            //从2开始分解,依次分解为2,3,4,5...连续的元素
            flag[i++] = k;
            num -= k;
            k++;
        }
        if(num > 0){
            //说明有剩余的
            if(num == flag[i-1]){
                //说明这时候剩余的数正好比已有的元素个数多1,所以要先给最后一个元素加1
                flag[i-1]++;
                num--;
            }
            for(int j=i-1;j>=0 &&num>0;j--){
                flag[j] ++;
                num--;
            }
 
        }
        int result = 1;
        for(int j = 0;j<i;j++){
            result *= flag[j];
        }
        cout<<result<<endl;
    }//while
    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>
usingnamespace std;
 
int main(){
    int num;
    while(cin>>num){
        if(num % 3 == 0){   //考虑被3整除的情况
            cout<<pow(3,num/3)<<endl;
            continue;
        }
        int flag[100] = {0};
        int i=0;
        while(num != 2 && num != 4){
            //如果不能被3整除,那么除3必余1或者2,而余1和4是同样的情况,这里取4是因为这种情况下最后是两个2,
            //取4就可以直接把4分解为2+2
            flag[i++]=3;
            num-=3;
        }
        while(num){  //余2和1的情况,余2就是1个2,余1就是2个2,所以前面才会判断是否等于4,这样就可以化为2个2
            flag[i++] = 2;
            num-=2;
        }
        int result = 1;
        for(int j=0;j<i;j++){
            result *= flag[j];
        }
        cout<<result<<endl;
    }//while
    return 0;
}


评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值