最佳加法表达式
Descriptions:
给定n个1到9的数字,要求在数字之间摆放m个加号(加号两边必须有数字),使得所得到的加法表达式的值最小,并输出该值。例如,在1234中摆放1个加号,最好的摆法就是12+34,和为36
Input
有不超过15组数据
每组数据两行。第一行是整数m,表示有m个加号要放( 0<=m<=50)
第二行是若干个数字。数字总数n不超过50,且 m <= n-1
Output
对每组数据,输出最小加法表达式的值
Sample Input
2
123456
1
123456
4
12345
Sample Output
102
579
15
Hint
要用到高精度计算,即用数组来存放long long 都装不下的大整数,并用模拟列竖式的办法进行大整数的加法。
题目链接:
https://vjudge.net/problem/OpenJ_Bailian-4152
dp[i][j]表示前i个数添加了j个加号得到的最小和。转移方程为 dp[i][j]=min(dp[x][j-1]+num[x+1][i]) 其中x>=j且x<i num[x+1][i]表示第x+1位到第i位组成的数。可能难理解,别光看,举个例子在纸上画画试试,有助于理解
AC代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <fstream> 4 #include <algorithm> 5 #include <cmath> 6 #include <deque> 7 #include <vector> 8 #include <queue> 9 #include <string> 10 #include <cstring> 11 #include <map> 12 #include <stack> 13 #include <set> 14 #include <sstream> 15 #define ME0(X) memset((X), 0, sizeof((X))) 16 using namespace std; 17 const int L=100; 18 string dp[100][100]; 19 string add(string a,string b)//只限两个非负整数相加 20 { 21 string ans; 22 int na[L]= {0},nb[L]= {0}; 23 int la=a.size(),lb=b.size(); 24 for(int i=0; i<la; i++) 25 na[la-1-i]=a[i]-'0'; 26 for(int i=0; i<lb; i++) 27 nb[lb-1-i]=b[i]-'0'; 28 int lmax=la>lb?la:lb; 29 for(int i=0; i<lmax; i++) 30 na[i]+=nb[i],na[i+1]+=na[i]/10,na[i]%=10; 31 if(na[lmax]) 32 lmax++; 33 for(int i=lmax-1; i>=0; i--) 34 ans+=na[i]+'0'; 35 return ans; 36 } 37 string mins(string a,string b)//判断大小 38 { 39 if(a.length()<b.length()) 40 return a; 41 else if(b.length()<a.length()) 42 return b; 43 else 44 return a<b?a:b; 45 } 46 int main() 47 { 48 int m; 49 string s; 50 while(cin >> m >> s) 51 { 52 s=" "+s; 53 int len=s.length(); 54 for(int i=0; i<=len; i++) 55 dp[i][0]=s.substr(1,i); 56 for(int j=1; j<=m; j++) 57 { 58 for(int i=0; i<=len; i++) 59 { 60 for(int x=j; x<i; x++) 61 { 62 //// 前x个数和"+"相等时,显然不成立,x个数最多有x-1个"+",所以要单独处理 63 if(x==j) 64 dp[i][j]=add(dp[x][j-1],s.substr(x+1,i-x)); 65 // 其他的情况,状态转移方程即可 66 else 67 dp[i][j]=mins(dp[i][j],add(dp[x][j-1],s.substr(x+1,i-x))); 68 } 69 } 70 } 71 cout << dp[len][m] << endl; 72 } 73 }