最优分解问题
问题描述:
设 n 是一个正整数。现在要求将 n 分解为若干互不相同的自然数的和,且使这些自然数的乘积最大。如 10 = 3+7 =
4+6 = 2+3+5 = ……
最大乘积为: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 |最小;同时又可以将其分解成尽可能多的因
子,且因子的值较大,确保最终所分解的自然数的乘积可以取得最大值
算法代码:
// #################################################### // 贪心算法解决 '整数最优分解' 问题. // #################################################### #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; }