动态规划-最佳加法表达式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()

 

posted @ 2020-05-30 19:32  StudyNLP  阅读(350)  评论(0编辑  收藏  举报