PKU acm 1651 multiplication puzzle

10 1 50 20 5

player might take a card with 1, then 20 and 50, scoring

10*1*50 + 50*20*5 + 10*50*5 = 500+5000+2500 = 8000

If he would take the cards in the opposite order, i.e. 50, then 20, then 1, the score would be

1*50*20 + 1*20*5 + 10*1*5 = 1000+100+50 = 1150.

不能取第一个和最后一个数字,我们的目的是将其余数字全部取出,并且使得按照规则计算的分数最小。

计分规则是,每取一个a, 计算 score.a = a.left * a * a.right然后将a取出,最后的总分是每次取出计算得出的分值总和。

 

动态规划,思路和矩阵连乘几乎一致。

考虑

10 1 50 20 5

对于最优解,取最后一个数字,假如说最后一个数字取的是50,那么其实

10 1 50

50 20 5

是两个子问题,他们也应该是最优的,而最后结果是

10 * 50 * 5 + best(10,1,50) + best(50,20,5)

 

best resutl  of li = best[0, len – 1]

 

best[i, j] =  min { li[i] * li[k] * li[j] + best[i, k] + best[k, j]} for k in range [i+1, j)

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int SolveDp(int a[], int num)
 5 {
 6     int result[num][num];
 7     for (int i = 0; i < num; i++)
 8         for (int j = 0; j < num; j++)
 9             result[i][j] = 0;
10 
11     //init delta = 2 a[0] a[1] a[2]
12     for (int i = 0; i < num - 2; i++)
13         result[i][i + 2= a[i] * a[i + 1* a[i + 2];
14 
15     for (int delta = 3; delta < num; delta++)
16         for (int i = 0; i < num - delta; i++) {
17             int minScore;
18             for (int j = i + 1; j < i + delta; j++) {
19                 int curScore = result[i][j] + result[j][i + delta] + 
20                                a[i] * a[j] * a[i +delta];
21                 if(j == i + 1)
22                     minScore = curScore;
23                 else if (curScore < minScore)
24                     minScore = curScore;
25             }
26             result[i][i + delta] = minScore;
27         }
28     return result[0][num - 1];
29 }
30 
31 int main(int argc, char *argv[])
32 {
33     //while(1) {
34         int num;
35         cin >> num;
36         int a[num];
37         for (int i = 0; i < num; i++)
38             cin >> a[i];
39         cout << SolveDp(a, num) << endl;
40     //}
41     return 0;
42 }

下面给出python写的,递归回溯(穷举),以及动态规划解法

 1 #递归回溯穷举
 2 def findMinScore(li):
 3     minScore = -1  #init,if not touched it will be < 0
 4     def findMinScoreRec(score = 0):
 5         nonlocal minScore
 6         length = len(li)
 7         for i in range(1, length - 1):
 8             val = li[i]
 9             newScore =  score + li[i - 1* val * li[i + 1]
10             if not minScore < 0 and newScore > minScore:
11                 return
12             if len(li) == 3:
13                 if minScore <or newScore < minScore:
14                     minScore = newScore
15                 return
16             li.pop(i)
17             findMinScoreRec(newScore)
18             li.insert(i, val)  #do not need to get back
19     print("min score is ", minScore);        
20     findMinScoreRec();
21     return minScore
22  1 #dp method
 2 def findMinScore(li):
 3     length = len(li)
 4     #below is wrong!!! when result[0][2] = 99 than result[i][2] = 99 why??
 5     #result = [[0] * length] * length  #result[length][length] 0 is must for elements of distance 2
 6     
 7     result = [[0   for   a   in   range(length)]   for   b   in   range(length)]
 8     
 9     for i in range(length - 2):
10         result[i][i + 2= li[i] * li[i + 1* li[i + 2]
11     
12     for delta in range(3, length):
13         for i in range(length - delta):
14             for j in range(i + 1, i + delta):
15                 curScore = result[i][j] + result[j][i + delta] \
16                     + li[i] * li[j] * li[i + delta]
17                 if (j == i + 1 or curScore < minScore):
18                     minScore = curScore
19             result[i][i + delta] = minScore
20     
21     return result[0][length - 1]
22 

原文地址:https://www.cnblogs.com/rocketfan/p/1569923.html