内存:64  时间:1

题目描述

有一个由1..9组成的数字串.问如果将m个加 号插入到这个数字串中,在各种可能形成的 表达式中,值最小的那个表达式的值是多少 。例如,在1234中摆放1个加号,最好的摆法就是12+34,和为36

输入

有不超过15组数据
每组数据两行。第一行是整数m,表示有m个加号要放( 0<=m<=17)
第二行是若干个数字。数字总数n不超过18,且 m <= n-1

输出

对每组数据,输出最小加法表达式的值

样例输入

2
123456
1
123456
4
12345

样例输出

102
579
15

提示

代码如下

#include<bits/stdc++.h>
#include<cstring>
#include<stdlib.h>
using namespace std;
const int MaxLen = 55;
const string maxv = "999999999999999999999999999999999999999999999999999999999";
string ret[MaxLen][MaxLen];
string num[MaxLen][MaxLen];
int cmp(string &num1,string &num2)
{
    int l1 = num1.length();
    int l2 = num2.length();
    if (l1 != l2)
    {
        return l1-l2;
    }
    else
    {
        for (int i=l1-1; i>=0; i--)
        {
            if (num1[i]!=num2[i])
            {
                return num1[i]-num2[i];
            }
        }
        return 0;
    }
}
void add (string &num1,string &num2,string &num3)
{
    //加法从低位到高位相加,那么需要将字符串倒过来
    int l1 = num1.length();
    int l2 = num2.length();
    int maxl = MaxLen,c = 0;        //c是进位标志
    for (int i=0; i<maxl; i++)
    {
        int t;
        if (i < l1 && i < l2)
        {
            t = num1[i]+num2[i]-2*'0'+c;
        }
        else if (i < l1 && i >= l2)
        {
            t = num1[i] - '0' + c;
        }
        else if (i >= l1 && i < l2)
        {
            t = num2[i] - '0' + c;
        }
        else
        {
            break;
        }
        num3.append(1,t%10+'0');
        c = t/10;
    }
    while (c)
    {
        num3.append(1,c%10+'0');
        c /= 10;
    }
}
int main()
{
    int m;                  //加号数目
    string str;             //输入的字符串
    while(cin >> m >> str)
    {
        //为了之后的加法计算先将这个字符串倒过来
        reverse(str.begin(),str.end());
        int n = str.length();
        for (int i=0; i<n; i++)
        {
            num[i+1][i+1] = str.substr(i,1);
        }
        for (int i=1; i<=n; i++) //求解对应的num[i][j]
        {
            for (int j=i+1; j<=n; j++)
            {
                num[i][j] = str.substr(i-1,j-i+1);
            }
        }
        //当加号数目为0
        for (int i=1; i<=n; i++)
        {
            ret[0][i] = num[1][i];
        }
        for (int i=1; i<=m; i++) //对于加号数目的枚举
        {
            for (int j=1; j<=n; j++) //对于长度的枚举
            {
                string minv = maxv;
                string tmp;
                for (int k=i; k<=j-1; k++)
                {
                    tmp.clear();
                    add(ret[i-1][k],num[k+1][j],tmp);
                    if (cmp(minv,tmp)>0)
                    {
                        minv = tmp;
                    }
                }
                ret[i][j] = minv;
            }
        }
        //将原先颠倒的字符串倒回来
        reverse(ret[m][n].begin(),ret[m][n].end());
        cout << ret[m][n] << endl;
    }
    return 0;
}

代码来源于互联网,仅供参考!