思路:
运用动态规划
设原始数字为s的字符串,下标从1开始
定义:dp[i][j] = 前i个数插入j个加号后形成的式子的结果的最小值
递推公式:dp[i][j] = min(dp[k][j-1]+num(k+1,i))(k=j到i-1)
边界条件:dp[i][0] = num(1,i);
记忆数组的形成过程如上图所示:
所以应该按照i从小到大,j从小到大的顺序生成
#include <cstdio>
#include <iostream>
#include <string>
using namespace std;
//大数加法
string add(string s1, string s2) {
string res;
int jin = 0;
for (int i = s1.length() - 1, j = s2.length() - 1; i > -1 || j > -1; i--, j--) {
res = ' ' + res;
int m, n;
if (i > -1) {
m = s1[i] - '0';
}
else {
m = 0;
}
if (j > -1) {
n = s2[j] - '0';
}
else {
n = 0;
}
res[0] = m + n + jin;
if (res[0] > 9) {
res[0] = res[0] % 10 + '0';
jin = 1;
}
else {
res[0] = res[0] + '0';
jin = 0;
}
}
if (jin == 1) {
res = '1' + res;
}
return res;
}
//大数比较(返回两个大数中较小的那个)
string mins(string s1, string s2) {
int m = s1.length();
int n = s2.length();
if (m > n) {
return s2;
}
else if (m < n) {
return s1;
}
else {
if (s1 > s2) {
return s2;
}
else {
return s1;
}
}
}
string dp[60][60];
int main() {
int m;
while (cin >> m) {
string s;
cin >> s;
s = ' ' + s;//改变下标
int i, j, k;
//边界条件
for (i = 0; i <= s.length() - 1; i++) {
dp[i][0] = s.substr(1, i);
}
for (i = 1; i <= s.length() - 1; i++) {
for (j = 1; j < i; j++) {
dp[i][j] = "-1";
for (k = j; k < i; k++) {
if (dp[i][j].compare("-1") == 0) {
dp[i][j] = add(dp[k][j - 1], s.substr(k + 1, i-k));
}
else {
dp[i][j] = mins(dp[i][j], add(dp[k][j - 1], s.substr(k + 1, i-k)));
}
}
}
}
// for (i = 0; i <= s.length() - 1; i++) {
// for (j = 0; j < i; j++) {
// cout << dp[i][j] << " ";
// }
// cout << endl;
// }
cout << dp[s.length() - 1][m] << endl;
}
return 0;
}