zoukankan      html  css  js  c++  java
  • 【动态规划】最佳加法表达式(百练oj4152)

    总时间限制:
    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

  • 相关阅读:
    字节序(Endian),大端(BigEndian),小端(LittleEndian)
    关于PHOTO SHOP CS9.0无法启动adobe updater 请重新安装应用程序和组件解决方法!
    工作·事业·人生
    多选列表Select之双击删除与添加Demo
    WIN7任务栏修复解决windows7任务栏不能停靠图标的问题
    ip地址被绑定,vmware无法共享上网,
    小屋·小篮子·祭
    基础知识提问:关于HashTable和List两个容器Add改变了属性的同一对象的问题
    [转载]正则表达式30分钟入门教程及MTracer(破解版)
    让程序更健壮,用错误还是抛异常?
  • 原文地址:https://www.cnblogs.com/mr-wei977955490/p/12593693.html
Copyright © 2011-2022 走看看