百练4152:最佳加法表达式(dp+高精度)
描述
给定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 都装不下的大整数,并用模拟列竖式的办法进行大整数的加法。
搞了半天的C++高精度,,结果还是可耻地用了java大数。。
1 import java.math.BigDecimal; 2 import java.math.BigInteger; 3 import java.util.Scanner; 4 5 public class Main { 6 static BigInteger INF = new BigInteger("9999999999999999999999999999999999999999999999999999999"); 7 public static void main(String[] args) { 8 // TODO Auto-generated method stub 9 Scanner sc = new Scanner(System.in); 10 BigInteger dp[][] = new BigInteger[55][55]; 11 int m,n; 12 BigInteger s; 13 14 while(sc.hasNext()) 15 { 16 m = sc.nextInt(); 17 s = sc.nextBigInteger(); 18 19 n = s.toString().length(); 20 21 //BigDecimal num[][] = new BigDecimal[n+1][n+1];//num[i][j]表示从s第i个数到第j个数组成的数字 22 /* 23 for(int i = 1;i<=n;++i) 24 for(int j = 0;j<=n;++j) 25 { 26 if(i<=j) 27 { 28 num[i][j] = new BigDecimal(s.toString().substring(i-1,j)); 29 } 30 } 31 */ 32 33 dp[0][0] = new BigInteger("0");//没有数字没有加号的最小值是0 34 for(int i = 1;i<=n;++i) 35 { 36 dp[i][0] = new BigInteger(s.toString().substring(0,i));//没有加号的情况下,最小值就是数字自己 37 } 38 39 for(int i = 0;i<=n;++i) 40 for(int j = 1;j<=m;++j) 41 { 42 43 dp[i][j] = INF; 44 if(i>=j+1)//j个加号能插入i个数字中 45 { 46 for(int k = j;k<i;++k) 47 { 48 dp[i][j] = dp[i][j].min(dp[k][j-1].add(new BigInteger(s.toString().substring(k,i)))); 49 } 50 } 51 } 52 53 System.out.println(dp[n][m]); 54 }//while 55 } 56 57 }
补一个师傅的C++做法,之后回来补
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 string Add(string &a, string &b) { 5 string sum; 6 int lena = a.length(); 7 int lenb = b.length(); 8 int i = 0; 9 int j = 0; 10 int carry = 0; 11 int number = 0; 12 while (i < lena || j < lenb) { 13 number = carry; 14 if (i < lena) number += (a[i++] - '0'); 15 if (j < lenb) number += (b[j++] - '0'); 16 sum += (number % 10 + '0'); 17 carry = number / 10; 18 } 19 if (carry == 1) { 20 sum = sum + '1'; 21 } 22 23 return sum; 24 } 25 26 //1大于 0等于 -1小于 27 int comp(string &a, string &b) { 28 if (a.length() > b.length()) return 1; 29 if (a.length() < b.length()) return -1; 30 for (int i = a.length() - 1; i >= 0; --i) { 31 if (a[i] > b[i]) 32 return 1; 33 else if (a[i] < b[i]) { 34 return -1; 35 } 36 } 37 return 0; 38 } 39 40 string maxSum(vector<vector<string>> &record, string& s, int start, int m) { 41 if (m == 0) return s.substr(start); 42 43 if (record[start][m] != "") { 44 return record[start][m]; 45 } 46 47 string &rec = record[start][m]; 48 string minNumber = s; 49 for (int i = start; i < s.length() - m; ++i) { 50 string sub = s.substr(start, i - start + 1); 51 string remain = maxSum(record, s, i + 1, m - 1); 52 string r = Add(sub, remain); 53 if (comp(minNumber, r) == 1) { 54 minNumber = r; 55 } 56 } 57 return rec = minNumber; 58 } 59 60 int main() 61 { 62 int m; 63 string s; 64 while (cin >> m) { 65 cin >> s; 66 if (m == 0) { 67 cout << s << endl; 68 continue; 69 } 70 reverse(s.begin(), s.end()); 71 vector<vector<string>> record(s.length(), vector<string>(m + 1, "")); 72 string sum = maxSum(record, s, 0, m); 73 reverse(sum.begin(), sum.end()); 74 cout << sum << endl; 75 } 76 return 0; 77 }