题目:
【分析】
先通过若干个简单例子来观察规律,摸索思路。例如十进制整数 1234 划分为 3 段可有如下情形:
1 × 2 × 34 = 68
1 × 23 × 4 = 92
12 × 3 × 4 = 144(满足要求的解)
以计算正整数 1234 的最大 3 乘积为例,即 I = 1234,n = 4,k = 3(将 1234 分为 3 段)。由于计算乘积时要使用整数中的“一段”数字,则定义 w(s,t) 表示 I 中从第 s 位到第 t 位组成的数,如 w(2,3)=23;按照动态规划算法处理问题的步骤,定义 m(i,j) 表示整数 I 的前 i 位分成 j 段所得的“最大 j 乘积”,显然所求的问题即为计算 m(n,k)。
根据上述定义,显然有:
(1)当 i < j 时(这种情况下整数 I 的前 i 位无法分成 j 段),定义 m(i,j) = 0;
(2)当 j = 1 时(分为 1 段),有 m(i,j) = m(i,1) = w(1,i);
(3)当 j > 1且 j <= i 时,从 I 中的前 d 位数字(d 从 1 循环到i-1)可得到“最大 j-1 乘积(即 j-1 分段)”,然后乘以剩下的数字(组成 1 段,为 w(d+1,i),即从 d+1 位开始,到 I 的第 i 位),写成状态方程即为:
计算过程中会建立 2 个二维数组 W 和 M,前者是 n x n 阵,储存w(s,t) 的值(表示 I 中从第 s 位到第 t 位组成的数);后者是 n x k 阵,储存 m(i,j) 的值 。以计算正整数 1234 的最大 3 乘积为例,即 I = 1234,n = 4,k = 3,则有:
综上,可得m(i,j)的递推关系如下:
代码:
// 使用的库定义
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// ######################################################################## //
// //
// 下面是数据定义区 //
// //
// ######################################################################## //
#define STR_LEN 100
#define TRUE 1
#define FALSE 0
//
// ######################################################################## //
// //
// 下面是各个子函数定义 //
// //
// ######################################################################## //
int CalcMaxKProduct( int n, int k, int **D, int **P ); //计算正整数的最大 k 乘积
void PrintProductMatrix( int n, int k, int **D, int **P );//显示计算数据
//
// ######################################################################## //
// //
// 下面是各个子函数的实现 //
// //
// ######################################################################## //
// 使用动态规划法计算两个字符串之间的编辑距离 ...
//
// 测试数据如下 :
// ( 1 ) 1234 划分为 3 段 : 12 * 3 * 4 = 144
// ( 2 ) 自行设计 2 个测试用例
int CalcMaxKProduct( int n, int k, int **D, int **P )
{
int i, j, t, maxv, tk;
//当i<j无法进行分段
for(i = 1;i <= n;i++) //分成一段 j=1
{
P[i][1]= D[1][i];
}
for(i = 1; i <= n;i++) //DP过程
{
for(j = 2;j <= i;j++) //当 j > 1且 j <= i 时,从 I 中的前 t 位数字(t 从 1 循环到i-1)可得到“最大 j-1 乘积(即 j-1 分段)
{
maxv = 0;
for(t = 1;t < i;t++)
{
if((tk = P[t][j-1]*D[t+1][i]) > maxv) //然后乘以剩下的数字(组成 1 段,为 D(t+1,i),即从 t+1 位开始,到 I 的第 i 位),
maxv = tk;
}
P[i][j] = maxv;
}
}
return P[n][k];
}
// 打印编辑距离矩阵 ...
void PrintProductMatrix( int n, int k, int **D, int **P )
{
int i, j;
// 打印 'D' ...
printf( "\t生成的整数分段值矩阵为 : \n" );
for(i=1 ; i<= n; i++)
{
for(j=1 ; j<= n; j++)
{
printf("%d ",D[i][j]);
printf(" ");
}
printf("\n");
}
printf( "\n\n" );
// 打印 'P' ...
printf( "\t生成的分段乘积矩阵为 : \n" );
for(i=1 ; i<= n; i++)
{
for(j=1 ; j<= k; j++)
{
printf("%d ",P[i][j]);
printf(" ");
}
printf("\n");
}
printf( "\n\n" );
}
//
// ######################################################################## //
// //
// 下面是主程序的实现 //
// //
// ######################################################################## //
int main()
{
char StrI[ STR_LEN ];
char StrK[ STR_LEN ];
int *I, n; // 储存输入的整数及其长度 ...
int k; // 输入的整数分为 'k' 段 ...
int **D, **P; // 二维数组, 储存整数的各个分段值及乘积值 ...
int i, j, MaxProduct;
int IsStop;
IsStop = FALSE;
while ( !IsStop )
{
// 清屏 ...
system( "cls" );
// 输入整数 'I' ...
printf( "\n\n\t请输入 < 整数 I 的值 > , 输入 < q / Q > 表示结束 : " );
scanf( "%s", StrI );
n = strlen( StrI ); // 输入整数的位数 ...
if ( n > 0 )
IsStop = ( ( StrI[ 0 ] == 'q' ) || ( StrI[ 0 ] == 'Q' ) );
else
printf( "\t输入的整数不能为空 !\n\n" );
if ( !IsStop )
{
// 输入分段数 'k' ...
printf( "\n\t请输入 < 整数分段数 k > , 输入 < q / Q > 表示结束 : " );
scanf( "%s", StrK );
if ( strlen( StrK ) > 0 )
IsStop = ( ( StrK[ 0 ] == 'q' ) || ( StrK[ 0 ] == 'Q' ) );
else
printf( "\t输入的整数分段数不能为空 !\n\n" );
// 输入的整数及其分段数 'I' 和 'k' 均不为空, 则计算最大 'k' 乘积 ...
if ( !IsStop )
{
// 将输入的字符串转换为整数 ...
// 输入的整数 'I' ...
// 动态申请一维数组 ...
I = ( int * )malloc( ( n + 1 ) * sizeof( int ) );
// 将输入的字符串整数的每一位放入 'I' 中 ...
for ( i = 1; i <= n; i++ )
I[ i ] = StrI[ i - 1 ] - '0'; // 注意序号起始值 ...
// 输入的分段数 'k' ...
k = atoi( StrK ); //把StrK(字符串)转换为一个整数
// 动态申请二维数组 'D' 和 'P' ...
// 'D' - 储存整数的各个分段值( n x n 阵 ) ...
//定义 D(s,t) 表示 I 中从第 s 位到第 t 位组成的数
D = ( int ** )malloc( ( n + 1 ) * sizeof( int ) );
for ( i = 0; i <= n; i++ )
D[ i ] = ( int * )malloc( ( n + 1 ) * sizeof( int ) );
// 初始化 ...
for ( i = 0; i <= n; i++ )
for ( j = 0; j <= n; j++ )
D[ i ][ j ] = 0;
// 'P' - 储存整数的分段乘积值( n x k 阵 ) ...
//定义 P(i,j) 表示整数 I 的前 i 位分成 j 段所得的“最大 j 乘积”
P = ( int ** )malloc( ( n + 1 ) * sizeof( int ) );
for ( i = 0; i <= n; i++ )
P[ i ] = ( int * )malloc( ( k + 1 ) * sizeof( int ) );
// 初始化 ...
for ( i = 0; i <= n; i++ )
for ( j = 0; j <= k; j++ )
P[ i ][ j ] = 0;
// 生成 'D' 矩阵 ...
//表示 I 中从第 s 位到第 t 位组成的数
for( i = 1 ;i <= n; i++ )
{
D[i][i] = I[i];
for(j = i+1;j <= n;j++)
{
D[i][j] = D[i][j-1]*10+I[j];
}
}
// 计算最大 'k' 乘积 ...
MaxProduct = CalcMaxKProduct( n, k, D, P );
// 显示计算结果 ...
printf( "\n\t< 计算得到的最大 k 乘积为:%d > \n\n", MaxProduct );
// 打印数值矩阵 ...
PrintProductMatrix( n, k, D, P );
// 释放二维数组 'D' 和 'P' 的空间 ...
for ( i = 0; i <= n; i++ )
free( D[ i ] );
free( D );
for ( i = 0; i <= n; i++ )
free( P[ i ] );
free( P );
// 等待用户输入任意一键返回 ...
printf( "\n\n" );
system( "PAUSE" );
}
}
}
// 等待用户输入任意一键返回 ...
printf( "\n\n" );
return 0;
}
//
运行结果: