POJ 13295 最佳加法表达式 【dp】【北大ACM/ICPC竞赛训练】

高精度写了半天

dp[i][j]代表前i个数字放j个加号的最小值。转移的时候枚举在第k个数字后放加号,那么k最大在i-1后放加号,最小在第j个数后面放加号。

O(i^2 * j)复杂度

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 struct bigN{
 6     int a[55],length;//从低位到高位 
 7     bigN(int num[],int len){//num是从高位到低位
 8         memset(a,0,sizeof(a));
 9         length = len;
10         for(int i=0;i<len;i++) a[i]=num[len-i-1];    
11     }
12     bigN(){
13         length=0;
14         memset(a,0,sizeof(a));
15     }
16     bigN operator + (bigN n1){
17         bigN ans;
18         ans.length = max(n1.length,length);
19         for(int i=0;i<ans.length;i++){
20             ans.a[i] += a[i] + n1.a[i];
21             ans.a[i+1] += ans.a[i]/10;
22             ans.a[i]%=10;  
23         }
24         if(ans.a[ans.length]!=0) ans.length++;
25         return ans;
26     }
27     bool operator < (bigN n1){//this是不是比n1小 
28         if( length>n1.length ) return false;
29         else if(length<n1.length) return true;
30         for(int i=length-1;i>=0;i--){//从高位比到低位 
31             if( a[i]>n1.a[i] ) return false;
32             else if( n1.a[i]>a[i] ) return true;
33         }
34         //相等
35         return false; 
36     }
37 }memo[55][55];
38 ostream& operator<< (ostream& os,const bigN& x){
39     for(int i=x.length-1;i>=0;i--) os<<x.a[i];
40     return os;
41 }
42 
43 bigN min(bigN n1,bigN n2){
44     if(n1<n2) return n1;
45     return n2;
46 }
47 
48 int s[55];
49 bigN dp(int i,int j){//前i个数字之间放j个加号的最小值
50     //cout<<i<<" "<<j<<endl;
51     if(memo[i][j].length!=0) return memo[i][j];
52     if(i-1==j){
53         bigN an;
54         for(int i1=1;i1<=i;i1++) an=an+bigN(s+i1,1);
55         return memo[i][j]=an;
56     }
57     if(j==0) return memo[i][j]=bigN(s+1,i);
58     
59     //枚举第j个加号放在第k个数字后 
60     bigN ans; ans.length=100;
61     for(int k=j;k<=i-1;k++){
62         bigN cnt = dp(k,j-1)+bigN(s+k+1,i-k);
63         ans = min(ans, cnt );
64     }
65 
66     return memo[i][j]=ans;
67 }
68 
69 
70 int main(){
71     int m;
72     while( scanf("%d",&m)!=EOF ){
73         string s1; cin>>s1;
74         for(int i=0;i<s1.length();i++) s[i+1]=int(s1[i])-48;
75         
76         for(int i=0;i<=54;i++)
77             for(int j=0;j<=54;j++) memo[i][j]=bigN();
78             
79         cout<<dp(s1.length(),m)<<endl;
80     }
81     
82     return 0;
83  } 

 

转载于:https://www.cnblogs.com/ZhenghangHu/p/9363582.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值