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 }
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 <0 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 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 <0 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
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