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 

你可能感兴趣的:(ACM)