描述
给定n个1到9的数字,要求在数字之间摆放m个加号(加号两边必须有数字),使得所得到的加法表达式的值最小,并输出该值。例如,在1234中摆放1个加号,最好的摆法就是12+34,和为36
输入
有不超过15组数据
每组数据两行。第一行是整数m,表示有m个加号要放( 0<=m<=50)
第二行是若干个数字。数字总数n不超过50,且 m <= n-1
输出
对每组数据,输出最小加法表达式的值
样例输入
2 123456 1 123456 4 12345
样例输出
102 579 15
提示
要用到高精度计算,即用数组来存放long long 都装不下的大整数,并用模拟列竖式的办法进行大整数的加法。
解题分析
这同样是一道非常经典的动态规划题目,我们需要去分析放置的加号的位置,然后去求一个最大的结果,本题难度上升的最大一个原因就是我们需要去处理一个高精度运算的问题,这个我们用一个结构体去完成就好了。然后确定一下递推公式,dp[i][j]=max(dp[i][j],dp[j][j-1]+num(j,i-1),dp[j+1][j-1]+num(j+1,i-1),....)。这里dp[i][j]表示考虑前i个数,插入j-1的加号得到的最大值。如果说i<=j,说明不支持那么多加号的插入,这个时候需要注意把此时的dp[i][j]设置为一个很大的数防止后面的过程中取。还有一种特殊情况是插入的加号的数量为0的时候,这个时候我们直接把整个表达式的值作为结果即可。
代码实现
#include <iostream>
#include <cmath>
#include <iomanip>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <list>
#include <bitset>
using namespace std;
struct Bigint{
char nums[500];
Bigint(const char *s) {
strcpy(nums,s);
}
Bigint(){
strcpy(nums,"0");
}
Bigint operator+(const Bigint& o){
int a[500]={0},b[500]={0},c[500]={0};
int lena=strlen(nums),lenb=strlen(o.nums);
for(int i=0,j=lena-1;i<lena;i++,j--){
a[i]=nums[j]-'0';
}
for(int i=0,j=lenb-1;i<lenb;i++,j--){
b[i]=o.nums[j]-'0';
}
int len=max(lena,lenb)+3;
int tmp=0;
for(int i=0;i<=len;i++){
c[i]=a[i]+b[i]+tmp;
tmp=c[i]/10;
c[i]%=10;
}
int pos=-1;
for(int i=len;i>=0;i--){
if(c[i]){
pos=i;
break;
}
}
if(pos==-1){
return Bigint("0");
}
else{
char tmp[500];
int i,j;
for(i=0,j=pos;i<=pos;i++,j--){
tmp[i]=c[j]+'0';
}
tmp[i]='\0';
return Bigint(tmp);
}
}
Bigint get(int i,int j){
char tmp[500];
int k=0;
for(int l=i;l<=j;l++){
tmp[k++]=nums[l];
}
tmp[k]='\0';
return Bigint(tmp);
}
bool operator<(const Bigint& o) const{
//cout<<nums<<" vs "<<o.nums<<endl;
int len1=strlen(nums);
int len2=strlen(o.nums);
if(len1==len2){
for(int i=0;i<len1;i++){
//cout<<nums[i]<<" "<<o.nums[i]<<endl;
if(nums[i]==o.nums[i]){
continue;
}
else{
return nums[i]-'0'<o.nums[i]-'0';
}
}
return false;
}
else{
return len1 < len2;
}
}
};
int main(){
int m;
int t=0;
while(cin>>m){
t++;
if(t>15) break;
char num[500];
cin >> num;
Bigint qwq(num);
int len=strlen(num);
Bigint dp[55][55];
for(int i=1;i<=len;i++){
for(int j=0;j<=m;j++){
if(j==0){
dp[i][j] = qwq.get(0,i-1);
}
else if(i<=j){
dp[i][j] = Bigint("999999999999999999999999999999999999999999999999");
}
else{
//cout<<i<<" "<<j<<endl;
Bigint tmp("999999999999999999999999999999999999999999999999");
for(int p=j; p<=i-1 ;p++){
tmp= min( dp[p][j-1] + qwq.get(p,i-1) , tmp );
}
dp[i][j]=tmp;
}
}
}
cout<<dp[len][m].nums<<endl;
}
return 0;
}