最近剛學了一下算法,看見有一個求最大k乘積的問題,這個問題可用動態規劃來解決.具體解釋如下:
/*
* ===========================================================================
*
* Filename: max_k_product.c
*
* Description: 動態規劃之最大k乘積問題
*
* Version: 1.0
* Created: 2013年11月21日 14時16分36秒
* Revision: none
* Compiler: gcc
* CopyRight: open , free , share
* Author: yexingkong(zhangbaoqing)
* Email: [email protected]
* Company: Xi'an University of post and Telecommunications
*
* ===========================================================================
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define ARRAY_SIZE 11 /*定義數組大小 */
/*1.問題描述:
* 設I是一個n位十進制整數,如果將I劃分爲k段,則可得到k個整數,這k個整數
* 的乘積稱爲I的一個K乘積,試設計一個算法,對於給定的I和K,求出I的最大乘積
*
*2.實現要求:
* 2.1: 對於給定的I和K,設計I的最大k乘積.
* 2.2: 由文件input.txt提供輸入數據。文件的第1行中有2兩個正整數n和k.正
* 整數 n是序列的長度,正整數k是分割的段數。在接下來的一行中是一個
* n位十進制整數(n <= 10)
* 2.3: 將結果輸出到文件output.txt。文件第一行中的舒適計算出來的最大K
* 乘積.
*
*
* 3.算法分析與設計:
* 3.1:求I的k段最大乘積,可理解爲在n位數中插入k-1個乘號,且使得各個整
* 數乘積最大
* 3.2: 要使k個數的乘積最大,則要使前k-1個數的乘積最大,同理,也要使前
* k-2個數的乘積最大,這說明此問題具有最優子結構和子問題重疊性,
* 故可用動態規劃方法來解。。
* 3.3: k_max(i,k)表示第1 ~ i位數中插入k個乘號所得的最大值,a[i,j]表示
* 第i~j位所組成的自然數.
* 3.4: 現在假設將I分成K段後的最大乘積位K_max(n,k),且最後一組數爲a(i,n),
* , 可得狀態轉移方程: k_max(i,k) = max( k_max(j,k-1) * a(j+1,i)).
*
* */
/* -------------------------------------------------------------------*/
/**
* @Synopsis= WriteFile 用來隨機生成長度爲n的正整數I,並將其存入文件
*
* @Returns= 用來驗證函數是否正確執行
*/
/* ----------------------------------------------------------------------------*/
int WriteFile()
{
int i,m=0;
int n = 0, k = 0;
int df[ARRAY_SIZE];
FILE *fp;
fp = fopen("input.txt","w");
if (NULL == fp)
{
perror("fopen");
exit(1);
}
srand((unsigned)time(NULL));
n = 9.0 * rand() / (RAND_MAX + 1.0) + 1; //整數I的長度(1<= n <= 10)
k = 1.0 * (n-1) * rand()/ (RAND_MAX + 1.0) + 1; //整數I的分爲k段(1 <= k <= n )
for (i = 0; i < n; i++)
{
m = 9.0 * rand() / (RAND_MAX + 1.0) ;
if (0 == i && 0 == m)
{
n -= 1;
continue;
}
df[i] = m;
}
fprintf(fp, "%d %d\n", n,k);
for (i=0;i < n; i++)
fprintf(fp, "%d",df[i]);
fclose(fp);
return 0;
}
/* -------------------------------------------------------------------*/
/**
* @Synopsis= ReadFile 從文件中讀取所保存的正整數I及其長度,和要分的段數
*
* @Param= a[] 用來存儲正整數I,info[]用來存儲I的長度和所要分的段數k
*
* @Returns= 檢驗函數是否正確執行
*/
/* ----------------------------------------------------------------------------*/
int ReadFile(char a[],int info[])
{
FILE *fp;
int i;
int I_length = 0;
fp = fopen("input.txt","r");
if (NULL == fp)
{
perror("fopen");
exit(1);
}
fscanf(fp,"%d%d\n",&info[0],&info[1]);
printf("%d %d\n",info[0],info[1]);
for (i = 1; i <= info[0]; i++)
{
fscanf(fp,"%c",&a[i]);
}
fclose(fp);
return 0;
}
/* -------------------------------------------------------------------*/
/**
* @Synopsis= intergration_num 將i~j位的十進制數合併成一個十進制數
*
* @Param= a[] 保存的是正整數I
* @Param= start 劃分的起始位
* @Param= end 劃分的終止位
*
* @Returns= 返回合併後的數值
*/
/* -------------------------------------------------------------------*/
int intergration_num(char a[],int start,int end)
{
long sum=0;
int i;
for (i = start; i <= end; i++)
{
sum = a[i] - 48 + sum * 10;
}
return sum;
}
/* -------------------------------------------------------------------*/
/**
* @Synopsis= count_max_k_product 計算最大k乘積
*
* @Param= a[] 存儲有正整數I
* @Param= I 保存的是正整數I的長度,
* @Param= K 保存的是所分的段數
* @Param = index[] 用來回溯記錄最近一次的劃分位置
* @Returns= 返回值用來驗證函數是否成功執行
*/
/* ----------------------------------------------------------------------------*/
int count_max_k_product(char a[], int I,int K,int index[])
{
int i,j;
int k_max[I][K] ; //k_max[i][j]表示1 ~ i十進制位分成j段所得的最大乘積
int sum =0, temp = 0;
//分成一段
if (1 == K)
{
sum = intergration_num(a,1,I);
return sum;
}
//假設先從最後一個數劃分開,然後再乘上前面的k-1個不同劃分的積,
//找最大值,然後從倒數第二個數劃分開,然後再乘上前面k-2個不同劃分的積,
//找到最大值,與前一個最大值比較得到最大值,然後從倒數第三個劃分開,一
//次類推,直到倒數第I-(K-1)個數爲止,
for (i = I; i >= K; i--)
{
index[K-1] = i-1; //表示在第i-1個的數後面劃分
temp = count_max_k_product(a,i-1,K-1, index,f) * intergration_num(a,i,I);
if (sum < temp)
{
sum = temp;
}
}
return sum;
}
int main(int argc, char *argv[])
{
int info[2];
char a[ARRAY_SIZE];
int sum=0;
int index[ARRAY_SIZE], fd[ARRAY_SIZE];
int i, j = 1;
//其下爲函數調用
WriteFile();
ReadFile(a,info);
sum = count_max_k_product(a,info[0],info[1],index);
printf("%s分成%d段的最大乘積: %d\n",a+1,info[1],sum );
return EXIT_SUCCESS;
}