標籤:
卡片遊戲
題目大意:給你一排卡片,你可以從從中抽一些卡片(但是不能抽最左和最右的卡片),每張卡片上有一個數字,當你從中抽出一張卡片後,你將得卡片的數字和卡片左右兩張卡片的數位乘積的分數,問當剩下最左和最右兩張卡片的時候,你可以得到的最小的分數?
這一題一看好像挺複雜的,但是如果我們換一個思維方式,這一題就會變得很熟悉
首先這一題是顯而易見的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\n", dp[1][N - 2]);50 }
DP:Multiplication Puzzle(POJ 1651)