動態規劃之 最大k乘積


                      最近剛學了一下算法,看見有一個求最大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;
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章