动态规划-最佳加法表达式V2
最佳加法表达式V2
描述
给定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
递推实现:dp[i][j]表示j个加号插入i个数的最小加法表达式。为了计算方便,第0行增加多个最大值,
i表示有多少个数字,j列表示有多少个加号
这里假设最大值是999999.
举例:3个加号,"12345"5个数字
递推的步骤:先计算每一行的第1列,没有放入加号最小值的情况。
第2次循环,计算每行,有1个加号最小值的情况;
第3次循环,计算每行有2个加号最小值的情况;
第4次循环,计算每行有3个加号最小值的情况;
举个数据说明:比如dp[4][2]=19的计算过程,表示4个数字,插入2个加号
那么这个k的值只有2或者3可以选择。
当如果是2时,表示“12”插入1个加号的最小值+34,因此等于dp[2][1]+34=37
当如果是3时,表示“123”插入1个加号的最小值+4,因此等于dp[3][1]+4=19,
19的值最小,因此dp[4][2]=19
因为我们都是把加入1个加号的最小值都计算出来了,当计算加入2个加号的时候,就可以利用
上1个加号的最小值,从而实现递推第2个加号的最小值。
通过不断的递推,二维列表的最后一行一列的值,既是整个表达式所求的最小值。
# matrix_value[i][j]表示数字串num_list[N]的第i位到第j位之间的数字串表示的数组
# 把输入的数字字符串,把每个位置数字的值存在二维数组,假设m=3,n=12345,
# 为了方便从1开始计算,所以多增加0为第一行,其数组内容为:
[[0, 0, 0, 0, 0, 0],
[0, 1, 12, 123, 1234, 12345],
[0, 0, 2, 23, 234, 2345],
[0, 0, 0, 3, 34, 345],
[0, 0, 0, 0, 4, 45],
[0, 0, 0, 0, 0, 5]]
dp[i][j] 表示前i个数字放入j个加号的最小加法表达式值
[[999999, 999999, 999999, 999999],
[1, 999999, 999999, 999999],
[12, 3, 999999, 999999],
[123, 15, 6, 999999],
[1234, 46, 19, 10],
[12345, 168, 51, 24]]
python算法实现:
1 def main(): 2 # m个加号 3 m = int(input()) 4 # numList把数组字符串转换为列表 5 num_list = list(str(input())) 6 # n个数字 7 n = len(num_list) 8 # 把n个数字的值存在一个二维数组中 9 matrix_value = [[0] * (n+1) for i in range(n+1)] 10 #dp[i][j] 表示前i个数字放入j个加号的最小加法表达式值 11 dp = [[999999] * (m+1) for i in range(n+1)] 12 num_list = [int(i) for i in num_list] 13 #为了遍历从1开始计算,所以在前面再增加个0 14 num_list.insert(0, 0) 15 # matrix_value二维数组存储字符串数字构成的各种数值 16 for i in range(1,len(num_list)): 17 for j in range(i,len(num_list)): 18 matrix_value[i][j] = matrix_value[i][j - 1] * 10 + num_list[j] 19 # i表示有几个数字,0表示没有加号的情况,比如dp[2][0]表示,2个数字0个加号表达式的值 20 dp[i][0] = matrix_value[1][i] 21 22 #递推 23 #遍历加号个数,从放1个加号开始递增,m个加号 24 for j in range(1,m+1): 25 #遍历2个、3个……直到n个数字,保证数字个数大于加号个数,求其表达式的加法最小值 26 #比如,放1个加号,至少需要2个数字,所以数字的个数i=j+1 27 for i in range(j+1,n+1): 28 #在有i个数字的情况下遍历最后一个加号可能的位置,k表示在第k个数后放加号 29 #因为dp[k][j-1]之前已经计算好了,表示在k这个位置放入看j-1个加号 30 #的最小值之前已经计算过,所以能直接使用,即递推的原理。 31 # 这里k表示放最后一个加号的位置因为可能有很多个,所以需要遍历找到最小值的那个 32 for k in range(j,i): 33 dp[i][j] = min(dp[i][j], dp[k][j-1] + matrix_value[k+1][i]) 34 35 print("加法最佳表达式的最小值:%.2f"%dp[-1][-1]) 36 37 38 if __name__ == '__main__': 39 main()