问题描述
- 有一个由1…9组成的数字串,如果将m个加号插入到这个数字串中,在各种可能形成的表达式中,值最小的那个表达式的值是多少?
解题思路
- 假定数字串长度是n,添完加号后,表达式的最后一个加号添在第i个数字后面,那么整个表达式的最小值,就等于在前i个数字中插入m-1个加号所能形成的最小值,加上第i+1到第n个数字所组成的数的值(i从1开始算)
- 设V(m,n)表示在n个数字中插入m个加号所能形成的表达式最小值,那么:
if m = 0
V(m,n) = n个数字构成的整数
else if n < m+1
V(m,n) = Inf
else
V(m,n) = Min{ V(m-1,i) + Num(i+1,n)} ( i = m...n-1)
- Num(i,j)表示从第i个数字到第j个数字所组成的数。数字编号从1开始算。
- 此操作复杂度是 O ( j − i + 1 ) \Omicron(j-i+1) O(j−i+1),可以预处理后存起来。
总时间复杂度: O ( m n 2 ) \Omicron(mn^2) O(mn2)。
-
若n表较大,long long不够存放运算过程中的整数,则需要使用高精度计算(用数组存放大整数,模拟列竖式做加法),复杂度为 O ( m n 3 ) \Omicron(mn^3) O(mn3)。
-
以下演示两种方法:一个是小数处理,一个是大精度数组处理
代码示例:
#include<stdio.h>
#define MaxSize 100
int input[MaxSize];
long long Num(int i, int j)//将i到j部分的整数组成一个数
{
long long int number = 0;
int p = i;
while(p <= j){
number = number*10 + input[p];
p++;
}
//printf("Num(%d, %d) = %d\n", i, j, number);
return number;
}
long long int Function(int m, int i, int j)
{
long long int num = 0, temp;
int k = 0;
if( m == 0 ){
//printf("Function(%d, %d, %d) = %d\n", m, i, j, Num(i, j));
return Num(i, j);}
else if( j-i < m ){
//printf("Function(%d, %d, %d) = !\n", m, i, j);
return;}
else
{
num = Function(m-1, i, i+m-1) + Num(i+m, j);
//printf("Function(%d, %d, %d) = %d\n", m, i, j, num);
for(k = m; k < j-i; k++)
{
temp = Function(m-1, i, i+k) + Num(i+k+1, j);
//printf("temp:%d, num:%d\n", temp, num);
if( num > temp )
num = temp;
}
//printf("Function(%d, %d, %d) = %d\n", m, i, j, num);
return num;
}
}
int main()
{
int n, i, m;
//printf("Input nums length and m:");
scanf("%d %d", &n, &m);
i = n;
while(n){
scanf("%d", &input[i-n]);
n--;
}
//printf("minValue is:");
printf("\n result = %ld", Function(m, 0, i-1));
return 0;
}
大精度计算
#include<stdio.h>
#include<string.h>
#define Maxsize 1000
char input[Maxsize];
void strInsert(char *str){
int len = strlen(str),i;
if(len>0)
str[len+1] = '\0';
for(i = len;i>0; i--)
str[i] = str[i-1];
}
void strAdd(char *str1, char *str2)
{
int i, j, jw = 0, value = 0;
char temp[Maxsize] = {'\0'};
//printf("**add :str1:%s, str2:%s\n", str1, str2);
i = strlen(str1) - 1;
j = strlen(str2) - 1;
for( ; i >= 0 || j >= 0; j--, i--)
{
strInsert(temp);
value = (i>=0?(str1[i]-'0'):0) + (j>=0?(str2[j]-'0'):0);
temp[0] = value%10 + jw + '0';
jw = value/10;
//printf("!!! value:%d, temp:%s, jw:%d\n", value, temp, jw);
}
if(jw){
strInsert(temp);
temp[0] = jw + '0';
}
//printf("*::*temp:%s", temp);
memset(str2, 0, sizeof(str2));
//str2[0] = '\0';
strcpy(str2, temp);
}
int strCmp(char *str1, char *str2)
{
int len1 = strlen(str1);
int len2 = strlen(str2);
int i = 0;
if(len1 > len2)
return 1;
else if(len1 < len2)
return 0;
else{
for(;i<len1;i++){
if(str1[i] < str2[i])
return 0;
else if(str1[i] > str2[i])
return 1;
}
return 1;
}
}
void Function(int m, char *str)
{
int k = 0,len;
char temp1[Maxsize] = {'\0'};
char temp2[Maxsize] = {'\0'};
char num[Maxsize] = {'\0'};
len = strlen(str);
if( m == 0 ){
return;}
else if( len < m )
return;
else
{
strncpy(temp1, str, m);
strncpy(num, str+m, len-m);
Function(m-1, temp1);
//printf("--before add temp1:%s, num:%s--\n", temp1,num);
strAdd(temp1, num);
//printf("str:%s, temp1:%s, num:%s\n",str, temp1, num);
for(k = m+1; k < len; k++)
{
memset(temp1, 0, sizeof(temp1));
memset(temp2, 0, sizeof(temp2));
//temp1[0] = '\0';
//temp2[0] = '\0';
strncpy(temp1, str, k);
strncpy(temp2, str+k, len-k);
Function(m-1, temp1);
strAdd(temp1, temp2);
if(strCmp(num ,temp2)){
//memset(num, 0, sizeof(num));
num[0] = '\0';
strcpy(num, temp2);
}
//printf("for----temp1:%s, num:%s\n", temp1, num);
}
memset(str, 0, sizeof(str));
//str[0] = '\0';
strcpy(str, num);
}
}
int main()
{
int m;
while(scanf("%d%s", &m, input) != EOF){
//printf("m:%d,input:%s\n", m, input);
Function(m, input);
printf("%s\n", input);
memset(input, 0, sizeof(input));
}
return 0;
}
- 此代码在百练上提交总是超时,心碎~~
- 有大佬帮忙看看,留言哦~
注:文中问题及代码参考 MOOC——《程序设计与算法》(北京大学 郭炜)