最优分解问题算法
设n是一个正整数。如今要求将n分解为若干互不相同的天然数的和,且使这些天然数的乘积最大。ide
算法设计:对于给定的正整数n,计算最优分解方案。google
数据输入:由文件 input.txt 提供输入数据。文件的第一行是正整数n。spa
结果输出:将计算出的最大乘积输出到文件output.txt。设计
输入文件示例code |
输出文件示例blog |
input.txtip |
output.txtci |
10get |
30 |
先对整数分解分析能够发现以下结论:
若 a + b = const,则 |a - b| 越小,a·b越大。
根据原问题的描述,须要将正整数n分解为若干互不相同的天然数的和,同时又要使天然数的乘积最大。当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 /************************************************* 2 File Name: optimal_decomposition.cpp 3 Functions: 最优分解问题求解 4 将正整数n分解为若干个天然数的和, 5 使这些天然数的乘积最大。 6 Author: Jeccey 7 Created: Jeccey 8 Last Change: 2013-07-03 9 **************************************************/ 10 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 15 const int MAX = 51; 16 int a[MAX - 1]; //记录所分解的天然数 17 18 int PIntdecomp(int n); 19 20 int main() 21 { 22 int n; 23 char ch; 24 25 26 FILE *fp1, *fp2; 27 if( (fp1=fopen("input.txt","r")) == NULL){ 28 printf("cannot open file!\n"); 29 exit(0); 30 } 31 fscanf(fp1,"%d",&n); 32 33 memset(a, 0, MAX*sizeof(int)); 34 35 if( (fp2=fopen("output.txt","w")) == NULL){ 36 printf("cannot open file!\n"); 37 exit(0); 38 } 39 fprintf(fp2,"%d\n",PIntdecomp(n)); 40 41 return 0; 42 } 43 44 /**************************************************** 45 Function name: PIntedecomp 46 Description: 将正整数n分解为若干个天然数的和, 47 保证所分解天然数的乘积最大并返回。 48 Arguments: n (int类型,且n<=437) 49 50 Returns: mresult, int 类型 51 n所分解的天然数的乘积,返回0表示错误 52 *****************************************************/ 53 int PIntdecomp(int n) 54 { 55 int k,j,mresult; 56 57 if (n < 1 ) //非正整数返回0 58 return 0; 59 if (n < 5) //若n<5,结果是其自己 60 return n; 61 else{ //若 n>= 5 62 k = 0; 63 a[k] = 2; 64 n -= 2; 65 /* 贪心策略:先从2开始分红连续天然数的和 */ 66 for (; n > a[k]; ){ 67 a[++k] = a[k-1] + 1; 68 n -= a[k]; 69 } 70 /* 若是剩下一个数,将其按后项优先的方式 71 均匀分给前面各项 */ 72 if (n == a[k]){ 73 a[k]++; 74 n--; 75 } 76 for (j = 0; j < n; j++){ 77 a[k-j]++; 78 } 79 /* 计算连乘积 */ 80 for(mresult = 1, j = 0; j <= k; j++){ 81 mresult *= a[j]; 82 } 83 84 return mresult; 85 } 86 }
n<4 —— 乘积<n
n≥4—— 1. 1和(n-1)→乘积<n,无效;
2. a和(n-a),且 2≤a≤n-2,分解使乘积增长(能够证实)。
若因子大于4则继续分解,直至a和(n-a)都小于4。
所以最终分解结果:全是2或3;又3×3>2×2×2,因此有三个2换成两个3。
最终结果:“M个3”或“M个3和一个2”或“M个三和两个2”
即 R=3^M 或 R=(3^M)×2或 R=(3^M)×4