DP:Multiplication Puzzle(POJ 1651)

                  

                  卡片游戏

  题目大意:给你一排卡片,你可以从从中抽一些卡片(但是不能抽最左和最右的卡片),每张卡片上有一个数字,当你从中抽出一张卡片后,你将得卡片的数字和卡片左右两张卡片的数字的乘积的分数,问当剩下最左和最右两张卡片的时候,你可以得到的最小的分数

  这一题一看好像挺复杂的,但是如果我们换一个思维方式,这一题就会变得很熟悉

  首先这一题是显而易见的DP(找最小值,不能取极限方式)

  首先他要我们抽卡片是吧,一开始我们可能会想到先抽一张看看,然后在扫一遍其他卡片看能否抽,但是这样带来的直接后果就是,我们很难对先前我们抽过的卡片进行分数的储存,那么可以这么想,如果我们在抽卡片之前,把左i张右j张的卡片的抽取已经记下来了(相当于是抽空了),然后我们再把这张卡片和i-1和j+1的卡片的乘积+左i张和右j张卡片的分数加起来不就等于我们当前抽的卡片的分数了吗!那么最后我们就可以维护一个最小值区间,把区间不断扩大到n-2(除掉最左和最右两张),那得出的值即是最后的最小分数

  而这个方法,正是矩阵乘法的顺序安排的思路,熟悉而亲切

  

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 static long long cards[100];
 6 static long long dp[100][100];
 7 
 8 void Search(const int);
 9 long long min(const long long, const long long);
10 
11 int main(void)
12 {
13     int N, i;
14     while (~scanf("%d", &N))
15     {
16         for (i = 0; i < N; i++)
17             scanf("%d", &cards[i]);
18         //memset(dp, 0, sizeof(dp));
19         Search(N);
20     }
21     return 0;
22 }
23 
24 long long min(const long long x, const long long y)
25 {
26     return x < y ?  x : y;
27 }
28 
29 void Search(const int N)
30 {
31     int i, j, k, pos;
32 
33     for (i = 1; i < N - 1; i++)
34         dp[i][i] = cards[i - 1] * cards[i] * cards[i + 1];
35     for (k = 1; k < N - 2; k++)
36     {
37         for (i = 1; i < N - 1 - k; i++)
38         {
39             pos = i + k;
40             dp[i][pos] = cards[i] * cards[i - 1] * cards[pos + 1] + dp[i + 1][pos];//注意cards的位置
41             for (j = i + 1; j < pos; j++)
42             {
43                 dp[i][pos] = min(dp[i][pos],
44                     cards[j] * cards[i - 1] * cards[pos + 1] + dp[i][j - 1] + dp[j + 1][pos]);
45             }
46             dp[i][pos] = min(dp[i][pos], cards[i - 1] * cards[pos] * cards[pos + 1] + dp[i][pos - 1]);
47         }
48     }
49     printf("%lld
", dp[1][N - 2]);
50 }
原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/4852660.html