- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
-
给定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 都装不下的大整数,并用模拟列竖式的办法进行大整数的加法。
- 来源
- Guo Wei
题解:
- 本题难点在于利用数组实现高精度运算,模拟加减乘除
- 假设数字串的长度为 n,求将 m 个加号放入该字符串所形成的最小值
- 首先,分解子问题,规定最后一个加号的位置,假设将最后一个加号放在第 i 个数字后面,这时该问题就变成了在前i个数字中插入m - 1个加号所形成的最小值,加上第i + 1到第 n 个数字所组成的数的值( i 从 1 算起)
- 所以可以定义一个字符串加的函数add,利用引用型参数传递值。注意:字符串相加减,一定要注意高低位之分,可以在之前将字符串反转(可用STL中的 reverse(str.begin() , str.end()) 函数)
-
1 void add(string &num1, string &num2, string &num3) { 2 int l1 = num1.length(); 3 int l2 = num2.length(); 4 int c = 0;//进位标志 5 int maxl = Maxlen; 6 7 for(int i = 0; i < maxl; i++) { 8 int t; 9 if(i < l1 && i < l2) { 10 t = num1[i] + num2[i] - 2 * '0' + c; 11 } 12 else if(i < l1 && i >= l2) { 13 t = num1[i] - '0' + c; 14 } 15 else if(i >= l1 && i < l2) { 16 t = num2[i] - '0' + c; 17 } 18 else { 19 break; 20 } 21 num3.append(1, t % 10 + '0'); 22 c = t / 10; 23 } 24 while (c) 25 { 26 num3.append(1,c%10+'0'); 27 c /= 10; 28 } 29 }
- 总代码:
-
1 #include<iostream> 2 using namespace std; 3 #include<cstring> 4 #include<string> 5 #include<algorithm> 6 #include<stdlib.h> 7 8 const int Maxlen = 55; 9 const string maxv = "9999999999999999999999999999999999999999999"; 10 string ret[Maxlen][Maxlen]; 11 string num[Maxlen][Maxlen]; 12 13 int cmp(string &num1, string &num2) { 14 int l1 = num1.length(); 15 int l2 = num2.length(); 16 if(l1 != l2) { 17 return (l1 - l2); 18 } 19 else { 20 for(int i = l1 - 1; i >= 0; i--) { 21 if(num1[i] != num2[i]) { 22 return (num1[i] - num2[i]); 23 } 24 } 25 return 0; 26 } 27 } 28 29 void add(string &num1, string &num2, string &num3) { 30 int l1 = num1.length(); 31 int l2 = num2.length(); 32 int c = 0;//进位标志 33 int maxl = Maxlen; 34 35 for(int i = 0; i < maxl; i++) { 36 int t; 37 if(i < l1 && i < l2) { 38 t = num1[i] + num2[i] - 2 * '0' + c; 39 } 40 else if(i < l1 && i >= l2) { 41 t = num1[i] - '0' + c; 42 } 43 else if(i >= l1 && i < l2) { 44 t = num2[i] - '0' + c; 45 } 46 else { 47 break; 48 } 49 num3.append(1, t % 10 + '0'); 50 c = t / 10; 51 } 52 while (c) 53 { 54 num3.append(1,c%10+'0'); 55 c /= 10; 56 } 57 } 58 59 int main() { 60 int m; 61 string str; 62 while(cin >> m >> str) { 63 //加法从低位到高位相加,那么需要将字符串倒过来 64 reverse(str.begin(), str.end()); 65 int n = str.length(); 66 for(int i = 0; i < n; i++) { 67 num[i + 1][i + 1] = str.substr(i, 1); 68 } 69 for(int i = 1; i <= n; i++) { 70 for(int j = i + 1; j <= n; j++) { 71 num[i][j] = str.substr(i - 1, j - i + 1); 72 } 73 } 74 75 for(int i = 1; i <= n; i++) {//加号数目为0的时候 76 ret[0][i] = num[1][i]; 77 } 78 for(int i = 1; i <= m; i++) { 79 for(int j = 1; j <= n; j++) { 80 string minv = maxv; 81 string temp; 82 for(int k = i; k <= j - 1; k++){//ret[m][n] = min(ret[m-1][i] + num[i+1][n]); 83 temp.clear(); 84 add(ret[i - 1][k], num[k + 1][j], temp); 85 if(cmp(temp, minv) < 0) { 86 minv = temp; 87 } 88 } 89 ret[i][j] = minv; 90 } 91 } 92 reverse(ret[m][n].begin(), ret[m][n].end()); 93 cout << ret[m][n] << endl; 94 } 95 return 0; 96 }
参考链接 https://blog.csdn.net/qq_35049196/article/details/58247829