最優分解問題算法
設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