最優分解問題貪心求解

問題描述

設m是一個正整數,現在要求將n分解爲若干個互不相同的自然數的和,且使得這些自然數的乘積最大。
注意:這個問題不同於剪繩子問題,因爲剪繩子問題可以使得每一段重複相等,而此問題必須使得劃分出來的每一個數都互斥。

算法設計

對於給定的正整數m,要求計算最優分解方案

數據輸入

輸入只有1行,表示整數m

輸入樣例1:

10

輸入樣例2:

100

數據輸出

輸出有兩行
第一行表示整數m劃分的各個自然數,每個數之間有一個空格,劃分的數按照升序排列。
第二行表示這個最大的乘積。
輸出樣例1:

2 3 5
30

輸出樣例2:

2 3 5 6 7 8 9 10 11 12 13 14
21794572800

思路

貪心算法。如果a+b=n,則|a-b|越小,那麼ab越大,如老師所講,可以將n分解成從2開始的連續自然數的和。
例如:輸入n=10,則可以分解爲 2、3、4,還剩下1不夠5,把這個1倒着加,4 -> 5。
所以,最終分解爲2,3,5,結果爲2
3*5=30。

證明見貪心算法-最優分解

代碼

#include <iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int a[101];//用來存入劃分的每個數
/*
貪心算法。如果a+b=n,則|a-b|越小,那麼a*b越大,如老師所講,可以將n分解成從2開始的連續自然數的和。
例如:輸入n=10,則可以分解爲 2、3、4,還剩下1不夠5,把這個1倒着加,4 -> 5。
所以,最終分解爲2,3,5,結果爲2*3*5=30。
*/
int main()
{
    int m;
    cin>>m;//輸入待劃分的整數
    a[1]=2;//使得互斥和乘積最大,a[1]=2,
    m=m-2;
    int i;
    //往後的數依次遞增直到不滿足條件爲止
    for(i=1;m>=a[i]+1;i++){
        a[i+1]=a[i]+1;
        m=m-a[i+1];
    }
    int n=i;//一共有n個數
    //將剩餘的不能劃分成的數m依次從後往前分配給每一個數,一次分配一個1
    //從後往前均勻分配
    while(m!=0){
       a[i]++;//對a[i]分配一個1
       m--;//剩下未分完的數減去1
       //一共有n個數,標號爲1-n,步長爲n
       //每次向前偏移距離1,offset=-1
       //初始標號start=1,末尾標號end=n
       //i=(i-start+offset)%n+start;
       i=(i-1-1+n)%n+1;//i在(1-n)中循環向前移動一個距離
    }
    //p用來存放最大乘積
    long long p=1;
    //輸出最後劃分出來的n個數
    for(int i=1;i<=n;i++){
        cout<<a[i]<<" ";
        p=p*a[i];
    }
    cout<<endl<<p;//輸出最大乘積
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章