您的位置:首页 > 其它

最佳加法表达式

2017-12-24 12:52 337 查看

最佳加法表达式

总时间限制: 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 都装不下的大整数,并用模拟列竖式的办法进行大整数的加法。

算法参考:http://www.cnblogs.com/quintessence/p/7206417.html 使用了高精度
http://www.cnblogs.com/Renyi-Fan/p/6970166.html 没有使用高精度,有详细分析

假定数字串长度是n,添完加号后,表达式的最后一个加号添加在第 i 个数字后面
那么整个表达式的最小值,就等于在前 i 个数字中插入 m – 1个加号所能形成的最小值,
加上第 i + 1到第 n 个数字所组成的数的值(i从1开始算)。

设V(m,n)表示在n个数字中插入m个加号所能形成
的表达式最小值,那么:
if m = 0
V(m,n) = n个数字构成的整数
else if n < m + 1
V(m,n) = ∞
else
V(m,n) = Min{ V(m-1,i) + Num(i+1,n) } ( i = m … n-1)
Num(i,j)表示从第i个数字到第j个数字所组成的数。数字编号从1开始算。此操作复杂度是O(j-i+1)
总时间复杂度:O(mn2) .(dp二维表已经加号的位置)

1 #include <stdio.h>
2 #include<string.h>
3
4 #define MaxLength 91
5 int m,len,a[MaxLength];
6 long long count=0;
7
8 void init(char str[],int a[]);
9 void add(int a[],int b[],int c[]);
10 int cmp(int a[],int b[]);
11 void fun(int m,int n,int min[]);
12 void num(int i,int j,int t[]);
13 void output(int minSum[]);
14
15 int main(int argc, char *argv[])
16 {
17     freopen("003.txt","r",stdin);
18     freopen("003.out","w",stdout);
19     char str[MaxLength];
20     int minSum[MaxLength];
21     int i;
22
23     while(scanf("%d%s",&m,str)!=EOF)
24     {
25         init(str,a);
26         len=a[0];
27         /*printf("%d\n",m);
28         for(i=1;i<=a[0];i++) printf("%d",a[i]);
29         printf("\n");*/
30         for(i=1;i<MaxLength;i++) { minSum[i]=9; }
31         minSum[0]=MaxLength+4;
32
33         fun(m,len,minSum);
34         output(minSum);
35     }
36
37     /*char str1[20]="1",str2[20]="234";
38     int aa[25],bb[25],cc[25];
39
40     init(str1,aa);
41     init(str2,bb);
42     for(int i=0;i<=aa[0];i++) printf("%d",aa[i]);printf("\n");
43     for(int i=0;i<=bb[0];i++) printf("%d",bb[i]);printf("\n");
44     add(aa,bb,cc);
45     for(int i=0;i<=cc[0];i++) printf("%d",cc[i]);printf("\n");*/
46
47     return 0;
48 }
49
50 /******************************************************************************/
51 /*输入一个字符串str表示高精度正整数
52   将str转换成int数组存储在a[]
53   a[0]存储str代表的数字的位数
54   str正序存储在a[]中
55 */
56 void init(char str[],int a[])
57 {
58     int i;
59     //memset(a,0,sizeof(int)*MaxLength);
60     a[0]=strlen(str);
61     for(i=1;i<=a[0];i++)
62         a[i]=str[i-1]-'0';
63 }
64 /******************************************************************************/
65 void fun(int m,int n,int min[])
66 {
67     int i,j,x[MaxLength]={0},y[MaxLength]={0},sum[MaxLength];
68     //printf("m=%d n=%d\n",m,n);
69     if(m==0)
70     {
71         num(1,n,min);
72     }
73     else if(n<m+1)
74     {
75         for(i=1;i<MaxLength;i++) { min[i]=9;}
76         min[0]=MaxLength+2;
77     }
78     else
79     {
80         for(i=0;i<MaxLength;i++) min[i]=9;
81         min[0]=MaxLength+2;
82
83         for(i=m;i<n;i++)
84         {
85             fun(m-1,i,x);
86             num(i+1,n,y);
87             add(x,y,sum);
88             if(cmp(sum,min)==-1)
89             {    for(j=0;j<=sum[0];j++) min[j]=sum[j];    }
90         }
91     }
92 }
93 /******************************************************************************/
94 void num(int i,int j,int t[])
95 {
96     count++;
97     //printf("%d\n",count);
98
99     int k;
100     t[0]=j-i+1;
101     for(k=1;i<=j;k++,i++) t[k]=a[i];
102 }
103 /******************************************************************************/
104 /*  输入高精度正整数a和b,计算c=a+b   */
105 void add(int a[],int b[],int c[])
106 {
107     int x=0,i=a[0],j=b[0],k=1;
108     //memset(c,0,sizeof(int)*MaxLength);
109     //这个地方初始化的字节数的解释:c[]从主调函数传过来,c的元素个数未知。
110     //sizeof(c)只能测出一个元素的字节数,而不是整个数组的字节数
111
112     while(i>0&&j>0)
113     {
114         c[k]=a[i]+b[j]+x;//x表示加法的进位
115         x=c[k]/10;    //新产生的进位
116         c[k]=c[k]%10; //只保留个位
117         k++;
118         i--;
119         j--;
120     }
121     while(i>0)
122     {
123         c[k]=a[i]+x;
124         x=c[k]/10;
125         c[k]=c[k]%10;
126         k++;
127         i--;
128     }
129     while(j>0)
130     {
131         c[k]=b[j]+x;
132         x=c[k]/10;
133         c[k]=c[k]%10;
134         k++;
135         j--;
136     }
137     c[k]=x;  //可能有向更高位的进位
138     if(c[k]==0) k--;
139     c[0]=k;
140
141     for(i=1,j=c[0];i<j;i++,j--)
142     {
143         x=c[i]; c[i]=c[j]; c[j]=x;
144     }
145 }
146 /******************************************************************************/
147 /*  比较a[]和b[]表示的两个高精度整数的大小,返回1表示a>b,0表示相等,-1表示a<b   */
148 int cmp(int a[],int b[])
149 {
150     int i;
151     if(a[0]<b[0]) return -1;
152     else if(a[0]>b[0]) return 1;
153     else
154     {
155         i=1;
156         while(i<=a[0]&&a[i]==b[i]) i++;
157         if(i>a[0]) return 0;
158         else if(a[i]<b[i])return -1;
159         else return 1;
160     }
161 }
162 /******************************************************************************/
163 void output(int minSum[])
164 {
165     int i;
166     for(i=1;i<=minSum[0];i++)
167     {
168         printf("%d",minSum[i]);
169     }
170     printf("\n");
171 }


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: