您的位置:首页 > 其它

【动态规划】最佳加法表达式(百练oj4152)

2020-04-26 19:08 1576 查看
总时间限制:
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]
 = min(ret[m-1][i] + num[i+1]
);
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]
.begin(), ret[m]
.end());
93         cout << ret[m]
 << endl;
94     }
95     return 0;
96 }

 参考链接 https://blog.csdn.net/qq_35049196/article/details/58247829

  • 点赞 1
  • 收藏
  • 分享
  • 文章举报
Mrwei_418 发布了19 篇原创文章 · 获赞 2 · 访问量 228 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: