最优分解问题
问题描述:
设 n 是一个正整数。现在要求将 n 分解为若干互不相同的自然数的和,且使这些自然数的乘积最大。如 10 = 3+7 =
4+6 = 2+3+5 = ……
最大乘积为:2 * 3 * 5 = 30
最大乘积为:2 * 3 * 5 = 30
问题分析:
整数的一个性质:若 a + b =N(常数),则| a - b |越小, a * b 越大
当 n < 4 时, n 的分解的乘积小于 n ;
当 n >= 4 时,n = 1 + ( n – 1 ) 因子的乘积也是小于 n ;
所以 n = a + ( n – a ),2 ≤ a ≤ n - 2,可以保证乘积大于 n,即越分解乘积越大。
算法设计:
采用贪心策略:
将 n 分成从 2 开始的连续自然数的和。如果最后剩下一个数,将此数在后项优先的方式下均匀地分给前面各项。该
贪心策略首先保证了正整数所分解出的因子之差的绝对值最小,即 | a – b |最小;同时又可以将其分解成尽可能多的因
子,且因子的值较大,确保最终所分解的自然数的乘积可以取得最大值
对剩下的一个数均匀分给前面的各项时,进行优化,对最后一个数除以前面项的个数,得到的整数最为一个基数,
给前面的每一项都加这个基数,然后对最后一个数对前面的项数取余,从后向前,每一项加1,直到余数为0,不在加
算法代码:
// ####################################################
// 贪心算法解决 '整数最优分解' 问题.
// ####################################################
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STR_LEN 100
#define TRUE 1
#define FALSE 0
int DoIntOptDecomposition( int n, int *a );
//分解整数,并且计算乘积
int DoIntOptDecomposition( int n, int *a )
{
int MaxProduct = 1; // 乘积
int k = 1;
int count = 2; // 从 '2' 开始处理
//将 'n' 分成连续的自然数
while((n - count) > 0)
{
n -= count;
a[k++] = count++;
}
//设置'a'数组的结束标记
a[k--] = -1;
//将最后剩下的一个数,以后项优先的方式均匀分给前面各项
int basicsNum = n / (k - 1); //前面项平均分配到的最低数量
int surplusNum = n % (k - 1); //剩余多的,分配给后项,每项分 '1'
while(k > 0)
{
a[k] += basicsNum;
if( surplusNum > 0 )
{
a[ k ] += 1;
surplusNum --;
}
k --;
}
//计算乘积
//k此时值为 '0',所有自增 '1'
while(k++, a[k] > 0)
{
MaxProduct *= a[k];
}
return MaxProduct;
}
int main( void )
{
char StrN[ STR_LEN ];
int *a, *p;
int n, MaxProduct;
int IsStop;
IsStop = FALSE;
while ( !IsStop )
{
system( "cls" );
// 输入字符串 'A' ...
printf( "\n\n\t请输入 < 待分解的整数 > , 输入 < q / Q > 表示结束 : " );
scanf( "%s", StrN );
if ( strlen( StrN ) > 0 )
IsStop = ( ( StrN[ 0 ] == 'q' ) || ( StrN[ 0 ] == 'Q' ) );
else
printf( "\t输入的整数不能为空 !\n\n" );
if ( !IsStop )
{
a = ( int * )malloc( STR_LEN * sizeof( int ) );
// 得到输入的整数值 ...
n = atoi( StrN );
// 整数最优分解 ...
MaxProduct = DoIntOptDecomposition( n, a );
// 显示计算结果 ...
printf( "\n\t< 整数最优分解乘积为:%d > \n", MaxProduct );
printf( "\n\t< 分解因子值为 > \n" );
int i = 1;
while(a[i] > 0)
{
printf("\t%d", a[i]);
i++;
}
free( a );
printf( "\n\n" );
system( "PAUSE" );
}
}
printf( "\n\n" );
system( "PAUSE" );
return 0;
}
测试结果: